【题目】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1493
【算法分析】
这题一开始被那个翻转给吓到了,但是画了个图以后发现只是将顺时针变成逆时针,位置全变成n+2-i而已。假如我们都当成是未翻转前去看的话,就很容易想到维护方法。
定义一个偏移量pyl(拼音= =),表示向右旋转了多少格。在搞一个bool型表示是否翻转。
然后翻转前的R操作,直接偏移量+x
如果是翻转后的话,那么就是-x,因为数字变逆时针了,你要全部当成翻转前的情况的话,就相当于逆时针转动。(画了图就比较好理解)
然后有了这些性质,就维护一棵线段树即可。
另外注意数组里的color和线段树里的同步问题。
总之就是一些细节的东西。
【其它】1A,居然垫底了
Rank Run ID User Memory Time Language Code Length Submit Time 1 5318 root 18164K 2839MS Pascal 5.70K 2009-07-08 11:37:16 2 8949 oimaster 29172K 3514MS Pascal 5.26K 2010-01-30 11:57:51 3 5545 pyf 24144K 3948MS Pascal 5.17K 2009-07-10 20:11:20 4 9596 sadness 26860K 4107MS G++ 6.31K 2010-02-18 20:57:45 5 5942 tracyhenry 37808K 4342MS Pascal 4.89K 2009-08-04 15:24:39 6 9366 lilymona 41140K 4592MS G++ 2.69K 2010-02-11 02:14:30 7 5547 xlmj531 17064K 4608MS Pascal 5.92K 2009-07-10 20:14:23 8 5544 tclsm1991 23176K 4686MS Pascal 7.96K 2009-07-10 20:09:27 9 5542 tclsm 23168K 4840MS Pascal 7.96K 2009-07-10 20:08:04 10 5828 wu3412790 44288K 4871MS Pascal 3.55K 2009-07-18 22:11:15 11 9641 edward_mj 30800K 4873MS G++ 4.13K 2010-02-19 21:25:25
【CODE】
#include 【题目】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1566 【算法分析】 这个是看了beyondvoid大牛才会得。。。关键在第一步转化。 首先,Ai^2可以看成对于相同输出序列的结果中,进行一个N^2的枚举可得。 即: 假设Ai=n 那么 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) ans++; 得出的ans就是Ai^2 所以就相当于走两个相同输出序列的方案数。 这样的话: 用f[x1,y1,x2,y2]表示X状态走到(x1,y1),Y状态走到(x2,y2),它们之前走的输出序列是相同的这种情况下的方案数。 ((x1,y1)表示上面已经弹了x1颗珠子出来,下面已经弹出了y1颗珠子出来。) 所以有 f[x1,y1,x2,y2]=以下各项之和。 f[x1-1,y1,x2-1,y2] 前提是(u[x1]==u[x2]) f[x1-1,y1,x2,y2-1] 前提是(u[x1]==d[y2]) f[x1,y1-1,x2-1,y2] 前提是(d[y1]==u[x2]) f[x1,y1-1,x2,y2-1] 前提是(d[y1]==d[y2]) 然后初始值f[0,0,0,0]=1 然后这样由于空间太吓人了,而状态X和状态Y是同步运动的,我们可以通过x1+y1-x2算出y2,于是就把第四维略去了。 三维的空间本来是可以过了,然后由于这个题库太犀利。。。数组开大了会变成system error,所以只得再搞一个滚动数组。然后没想到的是,位运算居然那么耗时,TLE掉了,然后我就先用变量把i&1和(i&1)^1存起来再做。至于里面呢,用减法代替取余是必须的,然后我看到用了好几次同一个f,每次j+1,k+1之流也许会变慢,于是我直接开指针把它表示出来。 【其它】不错,排到了第二。 Rank Run ID User Memory Time Language Code Length Submit Time 1 6774 moon5ckq 2088K 1029MS G++ 0.87K 2009-09-14 09:42:34 2 9615 edward_mj 2068K 1045MS G++ 1.42K 2010-02-19 01:16:37 【CODE】 #include 【题目大意】 给定一个Treap的结点,然后你可以修改某些权值,每修改一个权值,花费K的代价。然后整棵树的权为各点的权和,而点的权定义为深度*给定的频率。让你求修改权值+树权最小是多少。 【算法分析】 注意到一点,由于权值可以改变,所以它不一定还是满足原来性质的堆,但是由于数据值是不能改变的,所以它必然还是一颗二叉查找树。 如果中序遍历一颗二叉查找树的话,就会得到一个排好序的序列。 所以可以想象如果从叶子往上面合的话,相当于每次在连续的一段里取一个结点做子树的根,然后合并这个结点两边的子树。 所以可以看成是经典的区间型动态规划。 f[i,j,W]表示[i,j]这个区间内够成一棵子树,该子树的树根的权值>=W的最小权。 然后首先有f[i,j,W]=f[i,j,W+1] 然后如果i>j的话,取为0。 剩下的就是看修不修改权值了。 f[i,j,W]=max{ f[i,k-1,W]+f[k+1,j,W]+s[i,j]+K(修改权值) f[i,k-1,w[k]]+f[k+1,j,w[k]]+s[i,j] (前提是w[k]>=W,这就对应不修改权值) } 【其它】WA了一遍。。。囧,memset这东西在long long身上好像有点不同,以后不用就是。 【CODE】 #include void init(){ void sort(){ void work(){ int main(){ 维护数列 【问题描述】 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 操作编号 输入文件中的格式 说明 1. 插入 INSERT_posi_tot_c1_c2_…_ctot 在当前数列的第 posi 个数字后插入 tot 个数字:c1, c2, …, ctot;若在数列首插 入,则 posi 为 0 2. 删除 DELETE_posi_tot 从当前数列的第 posi 个数字开始连续 删除 tot 个数字 3. 修改 MAKE-SAME_posi_tot_c 将当前数列的第 posi 个数字开始的连 续 tot 个数字统一修改为 c 4. 翻转 REVERSE_posi_tot 取出从当前数列的第 posi 个数字开始 的 tot 个数字,翻转后放入原来的位置 5. 求和 GET-SUM_posi_tot 计算从当前数列开始的第 posi 个数字 开始的 tot 个数字的和并输出 6. 求和最 大的子列 MAX-SUM 求出当前数列中和最大的一段子列, 并输出最大和 【输入格式】 输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M表示要进行的操作数目。 第 2 行包含 N 个数字,描述初始时的数列。 以下 M 行,每行一条命令,格式参见问题描述中的表格。 【输出格式】 对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结果,每个答案(数字)占一行。 【输入样例】 9 82 -6 3 5 1 -5 -3 6 3GET-SUM 5 4MAX-SUM INSERT 8 3 -5 7 2DELETE 12 1MAKE-SAME 3 3 2REVERSE 3 6GET-SUM 5 4MAX-SUM 【输出样例】 -110110 【样例说明】 初始时,我们拥有数列 2 -6 3 5 1 -5 -3 6 3 执行操作 GET-SUM 5 4,表示求出数列中从第 5 个数开始连续 4 个数字之和,1+(-5)+(-3)+6 = -1: 2 -6 3 5 1 -5 -3 6 3 执行操作 MAX-SUM,表示要求求出当前数列中最大的一段和,应为 3+5+1+(-5)+(-3)+6+3 = 10: 2 -6 3 5 1 -5 -3 6 3 执行操作 INSERT 8 3 -5 7 2,即在数列中第 8 个数字后插入-5 7 2, 2 -6 3 5 1 -5 -3 6 -5 7 2 3 执行操作 DELETE 12 1,表示删除第 12 个数字,即最后一个: 2 -6 3 5 1 -5 -3 6 -5 7 2 执行操作 MAKE-SAME 3 3 2,表示从第 3 个数开始的 3 个数字,统一修改为 2: 2 -6 3 5 1 -5 -3 6 -5 7 2 改为 2 -6 2 2 2 -5 -3 6 -5 7 2 执行操作 REVERSE 3 6,表示取出数列中从第 3 个数开始的连续 6 个数: 2 -6 2 2 2 -5 -3 6 -5 7 2 如上所示的灰色部分 2 2 2 -5 -3 6,翻转后得到 6 -3 -5 2 2 2,并放回原来位置: 2 -6 6 -3 -5 2 2 2 -5 7 2 最后执行 GET-SUM 5 4 和 MAX-SUM,不难得到答案 1 和 10。 2 -6 6 -3 -5 2 2 2 -5 7 2 【评分方法】 本题设有部分分,对于每一个测试点: 请注意:如果你的程序只能正确处理某一种操作,请确定在输出文件正确的位置上打印结果,即必须为另一种操作留下对应的行,否则我们不保证可以正确评分。 【数据规模和约定】 【题目大意】 给定一个数列,有插入数列,删除区间,区间修改为同一个值,区间翻转,求区间和,求整个数列的最大子段和这几个操作。 【算法分析】 号称历年NOI最BT的数据结构题。 利用Splay,把要操作的区间的前驱和后继分别Splay到根和根的右结点,然后中间的部分就会聚集在根的右结点的左子树下。这样就可以进行想要的操作了。。。 然后剩下的各种操作的维护的话,你可以把这棵平衡树当成线段树来处理,不过多了一个当前结点,复杂了很多。。。 【其它】 开始在SBT上搞了个类似Splay的操作。。。但是老WA,后来想想还是直接Splay吧。。。 这题做了一整天…速度和beyondvoid的差不多,= =也许是因为我基本上模仿他的吧~ 不过那个pushdown确实精妙。。。update的话,我是把维护父亲这一项都搞进去了。。。管他是不是都update一下。另外要注意的,pushdown以后的ml,mr,ms才是可用的。否则可能是虚假的。。。所以我在update里加了pushdown。另外比较猥琐的是第二个数据的话,有一个时刻数列中的数权<0,这样那个ms就要注意一下不能取null里的0值了,注意一下就成。 【CODE】 #include struct Splaytype{ void update(Node *x){ void pushdown(Node *x){ void rotate(Node *x,char op){ Node* newnode(int key){ void init(){ void Splay(Node *x,Node *pos){ Node* findpos(int pos){ void ins(int st,int n){ void del(int l,int r){ void makesame(int l,int r,int C){ void reverse(int l,int r){ int getsum(int l,int r){ int main(){ 【算法分析】 以前用SBT做过了,不过为了学习Splay,又用它来做测试了。。。 第一次写Splay,先写了个非指针版的。。。一直WA,后来模范beyondvoid大牛的一些技巧,写了个指针版的才AC。。。 【其它】 居然比SBT快。。。 不过SBT以前用pascal写的,现在是C++,另外我觉得我的SBT使用递归也是一个重要原因吧。 【CODE】 #include int main(){[NOI2009 day2 管道取珠]动态规划、巧妙转化**
[NOI day1 2009 二叉查找树]区间动态规划
const long long N=72;
const long long inf=(long long)(0x7FFFFFFF/2)*(long long)(0x7FFFFFFF/2);
long long n,cost;
long long key[N],w[N],ss[N],f[N][N][N],s[N][N];
long long pos[N],lw[N];
cin >> n >> cost;
for (long long i=1;i<=n;i++) cin >> key[i];
for (long long i=1;i<=n;i++) cin >> w[i];
for (long long i=1;i<=n;i++) cin >> ss[i];
for (long long i=1;i<=n;i++){
pos[i]=i;
lw[i]=w[i];
}
}
long long i,j,tmp;
for (i=1;i
if (lw[i]>w[j]){
tmp=lw[i]; lw[i]=lw[j]; lw[j]=tmp;
tmp=pos[i]; pos[i]=pos[j]; pos[j]=tmp;
}
for (i=1;i<=n;i++) w[pos[i]]=i;
for (i=1;i
if (key[i]>key[j]){
tmp=key[i]; key[i]=key[j]; key[j]=tmp;
tmp=w[i]; w[i]=w[j]; w[j]=tmp;
tmp=ss[i]; ss[i]=ss[j]; ss[j]=tmp;
}
for (i=1;i<=n;i++){
s[i][i]=ss[i];
for (j=i+1;j<=n;j++)
s[i][j]=s[i][j-1]+ss[j];
}
}
long long len,i,j,k,W;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
f[i][j][n+1]=inf;
for (i=0;i<=n;i++)
for (k=1;k<=w[i];k++)
f[i][i][k]=ss[i];
for (len=0;len
j=i+len;
for (W=n;W>=0;W–){
f[i][j][W]=f[i][j][W+1];
for (k=i;k<=j;k++){
if (f[i][k-1][W]+f[k+1][j][W]+s[i][j]+cost
if (w[k]>=W && f[i][k-1][w[k]]+f[k+1][j][w[k]]+s[i][j]
}
}
}
cout << f[1][n][1] << endl;
}
freopen("treapmod.in","r",stdin);
freopen("treapmod.out","w",stdout);
init();
sort();
work();
return 0;
} [NOI2005 day1 维护数列]Splay、平衡树上的线段树**
const int inf=500000000;
int a[500001];
struct Node{
Node *l,*r,*fa;
int s,ms,ml,mr,sum,sn,key; // sn for samenum mx for max_x
bool same,rev;
};
Node *root,*null,sp[4000111];
int tot;
if (x==null) return;
bool l=false,r=false;
if (x->l!=null) {l=true; x->l->fa=x; pushdown(x->l);}
if (x->r!=null) {r=true; x->r->fa=x; pushdown(x->r);}
x->s=x->l->s+x->r->s+1;
x->sum=x->l->sum+x->r->sum+x->key;
x->ms=x->key;
if (l) x->ms=max(x->ms,x->l->ms);
if (r) x->ms=max(x->ms,x->r->ms);
if (l) x->ms=max(x->ms,x->l->mr+x->key);
if (r) x->ms=max(x->ms,x->r->ml+x->key);
if (l && r) x->ms=max(x->ms,x->l->mr+x->r->ml+x->key);
x->ml=x->l->sum+x->key;
if (l) x->ml=max(x->ml,x->l->ml);
if (r) x->ml=max(x->ml,x->l->sum+x->key+x->r->ml);
x->mr=x->r->sum+x->key;
if (r) x->mr=max(x->mr,x->r->mr);
x->mr=max(x->mr,x->r->sum+x->key+x->l->mr);
}
if (x==null) return;
if (x->rev){
x->rev=false;
swap(x->l,x->r);
if (x->l!=null) x->l->rev=!x->l->rev;
if (x->r!=null) x->r->rev=!x->r->rev;
swap(x->ml,x->mr);
}
if (x->same){
x->same=false;
if (x->l!=null) {x->l->same=true; x->l->sn=x->sn;}
if (x->r!=null) {x->r->same=true; x->r->sn=x->sn;}
x->key=x->sn;
x->sum=x->s*x->key;
x->ms=x->ml=x->mr=max(x->sum,x->key);
}
}
Node *y=x->fa;
if (op==’l’){y->r=x->l; x->l=y;}
else{y->l=x->r; x->r=y;}
if (y->fa->l==y) y->fa->l=x;
else y->fa->r=x;
x->fa=y->fa;
update(y);
update(x);
}
Node *p=&sp[++tot];
p->l=null; p->r=null; p->fa=null;
p->s=1; p->ms=p->ml=p->mr=p->sum=p->key=key;
p->sn=0; p->same=false; p->rev=false;
return p;
}
Node *p,*q;
tot=0;
null=&sp[0];
null->l=null; null->r=null; null->fa=null;
null->s=null->ms=null->ml=null->mr=null->sum=null->sn=0;
null->same=null->rev=false; null->key=0;
root=newnode(-inf);
p=newnode(-inf);
q=newnode(-inf);
root->l=q;
q->l=p;
update(q);
update(root);
}
if (x==null || x==pos) return;
pushdown(x);
Node *y,*z;
while (x->fa!=pos){
y=x->fa; z=y->fa;
if (z==pos)
if (y->l==x) rotate(x,’r’);
else rotate(x,’l’);
else if (z->l==y)
if (y->l==x) {rotate(y,’r’); rotate(x,’r’);}
else {rotate(x,’l’); rotate(x,’r’);}
else
if (y->r==x) {rotate(y,’l’); rotate(x,’l’);}
else {rotate(x,’r’); rotate(x,’l’);}
}
}
int done=0;
Node *p=root;
for (;;){
pushdown(p);
if (done+p->l->s+1==pos) return p;
if (done+p->l->s+1
}
}
st=min(st,root->s-2);
Node *p=findpos(st),*q=findpos(st+1),*tmp;
Splay(p,root);
Splay(q,p);
for (int i=1;i<=n;i++){
tmp=newnode(a[i]);
if (i
for (int i=1;i
update(tmp);
}
q->l=tmp;
update(q);
update(p);
update(root);
}
r=min(r,root->s-2);
Node *p=findpos(l-1),*q=findpos(r+1);
Splay(p,root);
Splay(q,p);
q->l=null;
update(q);
update(p);
update(root);
}
r=min(r,root->s-2);
Node *p=findpos(l-1),*q=findpos(r+1);
Splay(p,root);
Splay(q,p);
q->l->same=true;
q->l->sn=C;
update(q);
update(p);
update(root);
}
r=min(r,root->s-2);
Node *p=findpos(l-1),*q=findpos(r+1);
Splay(p,root);
Splay(q,p);
q->l->rev=true;
update(q);
update(p);
update(root);
}
r=min(r,root->s-2);
Node *p=findpos(l-1),*q=findpos(r+1);
Splay(p,root);
Splay(q,p);
pushdown(q->l);
return q->l->sum;
}
}Splay;
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
Splay.init();
char op[100]; int n,m,pos;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
Splay.ins(1,n);
for (int i=1;i<=m;i++){
scanf("%s",&op);
switch (op[0]){
case ‘I’:
scanf("%d%d",&pos,&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
Splay.ins(pos+1,n);
break;
case ‘D’:
scanf("%d%d",&pos,&n);
Splay.del(pos+1,pos+n);
break;
case ‘M’:
if (op[2]==’K’){
int C;
scanf("%d%d%d",&pos,&n,&C);
Splay.makesame(pos+1,pos+n,C);
}
else{
Splay.pushdown(Splay.root);
printf("%dn",Splay.root->ms);
}
break;
case ‘R’:
scanf("%d%d",&pos,&n);
Splay.reverse(pos+1,pos+n);
break;
case ‘G’:
scanf("%d%d",&pos,&n);
printf("%dn",Splay.getsum(pos+1,pos+n));
break;
}
}
}[NOI2004 郁闷的出纳员]我的第一个Splay
int limit,ss;
struct Splaytype{
struct Splaynode{
Splaynode *l,*r,*fa;
int key,s;
};
Splaynode space[1000000],*root,*p,*q,*null;
int tot;
void init(){
null=&space[0];
null->l=null;
null->r=null;
null->fa=null;
null->s=0;
tot=1;
Splaynode *p=&space[tot];
p->l=null;
p->r=null;
p->fa=null;
p->key=inf;
p->s=1;
root=p;
}
inline void update(Splaynode *x){
if (x==null) return;
x->s=x->l->s+x->r->s+1;
}
void zag(Splaynode *x){
Splaynode *y=x->fa;
y->r=x->l;
x->l=y;
if (y->fa->l==y) y->fa->l=x;
else y->fa->r=x;
x->fa=y->fa;
y->fa=x;
y->r->fa=y;
update(y);
update(x);
}
void zig(Splaynode *x){
Splaynode *y=x->fa;
y->l=x->r;
x->r=y;
if (y->fa->l==y) y->fa->l=x;
else y->fa->r=x;
x->fa=y->fa;
y->fa=x;
y->l->fa=y;
update(y);
update(x);
}
void Splay(Splaynode *x,Splaynode *pos){
if (x==root) return;
Splaynode *y,*z;
while (x->fa!=pos){
y=x->fa; z=y->fa;
if (z==pos)
if (y->l==x) zig(x);
else zag(x);
else if (z->l==y)
if (y->l==x) {zig(y); zig(x);}
else {zag(x); zig(x);}
else
if (y->r==x) {zag(y); zag(x);}
else {zig(x); zag(x);}
}
}
void ins(int key){
p=root->l,q=root;
for (;;){
if (p==null){
p=&space[++tot];
p->l=null;
p->r=null;
p->s=1;
p->key=key;
p->fa=q;
if (key
break;
}else
if (key
p=p->l;
}
else{
q=p;
p=p->r;
}
}
q=p;
for (;p!=null;p=p->fa) update(p);
Splay(q,root);
}
void del(){
p=root->l; q=root;
for (;;){
if (p==null){
Splay(q,root);
if (q->key+ss
if (q->r!=null) q->r->fa=root;
update(root);
}
else{
q->l=null;
update(q);
update(root);
}
return;
}else
if (p->key+ss>=limit){
q=p;
p=p->l;
}
else{
q=p;
p=p->r;
}
}
}
int get(int rank){
if (rank>root->s) return -1;
int done=0,td;
p=root;
for (;;){
if (done+p->r->s+1==rank) return p->key+ss;
if (done+p->r->s+1>rank) p=p->r;
else{
done+=p->r->s+1;
p=p->l;
}
}
}
}Splay;
freopen("cashier.in","r",stdin);
freopen("cashier.out","w",stdout);
Splay.init();
int n,x,innum=1; char ch;
scanf("%d%d",&n,&limit);
for (int i=1;i<=n;i++){
for (ch=getchar();ch==’ ‘ || ch==’n’;ch=getchar());
scanf("%d",&x);
switch (ch){
case ‘I’:if (x
case ‘S’:ss-=x; Splay.del(); break;
case ‘F’:printf("%dn",Splay.get(x+1)); break;
}
}
printf("%dn",innum-Splay.root->s);
}