1500: [NOI2005]维修数列
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 12544 Solved: 3970
[Submit][Status][Discuss]
Description
Input
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Output
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Sample Input
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
Sample Output
10
1
10
HINT
Source
打掉大boss了,一边抄一边写。
因为插入的数总共为4000000个,所以我们可以暴力地每个点直接插入,插入时,我们把新插入的元素建成一棵小树,再挂到大树上。
删除一样,转到那个节点,然后删除,但是这里要一个个删除,因为内存要循环利用。直接暴力删除,把节点放进一个栈中,用的时候拿出来,因为一共只有4000000个元素,绝对不会超时。
修改是打一个懒标记,tag[x]=c,然后pushdown即可。
翻转同上。
求和也是利用标记,sum[x]=sum[child[x][0]]+sum[child[x][1]]+key[x]
最后一个我们需要维护三个值,x节点表示的区间,lm[x]表示从x节点的区间最左端开始,最大的和是多少,rm[x]则是右边,mx[x]则表示这个节点的最大和
mx[x]=max(mx[child[x][0]],mx[child[x][1]],max(rm[child[x][0]],0)+key[x]+max(0,lm[child[x][1]])) 自己拿手画一下,想一下即可。
注意:pushdown要更新自己的sum[x],key[x],然后也要把自己的儿子节点child[x][0],child[x][1]也更新掉,翻转也是,我不知道为什么,这里查了两个小时才发现。
makesame的初始值要设成-1001,因为更新的数在[-1000,1000]之间。
#include<cstdio> #include<cstring> #include<stack> #include<vector> using namespace std; #define N 1000010 #define inf -1101 stack<int> s; int n,m,root,cnt; int size[N],child[N][2],lm[N],rm[N],key[N],mx[N],sum[N]; int tag1[N],tag2[N],fa[N],a[N]; void update(int x) { size[x]=size[child[x][0]]+size[child[x][1]]+1; sum[x]=sum[child[x][0]]+sum[child[x][1]]+key[x]; mx[x]=max(max(mx[child[x][0]],mx[child[x][1]]), max(rm[child[x][0]],0)+key[x]+max(lm[child[x][1]],0)); lm[x]=max(lm[child[x][0]],sum[child[x][0]]+key[x]+max(0,lm[child[x][1]])); rm[x]=max(rm[child[x][1]],sum[child[x][1]]+key[x]+max(0,rm[child[x][0]])); } void paint(int x) { tag2[x]^=1; swap(child[x][0],child[x][1]); swap(lm[x],rm[x]); } void paint(int x,int c) { if(!x) return; tag1[x]=key[x]=c; sum[x]=size[x]*c; lm[x]=rm[x]=mx[x]=max(sum[x],key[x]); } void pushdown(int x) { if(tag1[x]!=inf) { paint(child[x][0],tag1[x]);//更新儿子节点 paint(child[x][1],tag1[x]);//更新儿子节点 tag1[x]=inf; } if(tag2[x]) { tag2[x]^=1; if(child[x][0]) paint(child[x][0]);//更新儿子节点 if(child[x][1]) paint(child[x][1]);//更新儿子节点 } } void zig(int x) { int y=fa[x]; fa[x]=fa[y]; child[fa[x]][child[fa[x]][1]==y]=x; child[y][0]=child[x][1]; fa[child[x][1]]=y; child[x][1]=y; fa[y]=x; update(y); update(x); } void zag(int x) { int y=fa[x]; fa[x]=fa[y]; child[fa[x]][child[fa[x]][1]==y]=x; child[y][1]=child[x][0]; fa[child[x][0]]=y; child[x][0]=y; fa[y]=x; update(y); update(x); } void splay(int x,int t) { while(fa[x]!=t) { pushdown(x); int y=fa[x],z=fa[y]; if(z==t) { x==child[y][0]?zig(x):zag(x); break; } x==child[y][0]?zig(x):zag(x); x==child[z][0]?zig(x):zag(x); } if(!t) root=x; update(root); } int find(int x,int rank) { pushdown(x); if(size[child[x][0]]+1==rank) return x; if(size[child[x][0]]>=rank) return find(child[x][0],rank); else return find(child[x][1],rank-size[child[x][0]]-1); } int newnode() { int ret=0; if(!s.empty()) { ret=s.top(); s.pop(); } else ret=++cnt; return ret; } void build(int l,int r,int&x,int last) { int mid=(l+r)>>1; x=newnode(); key[x]=a[mid]; fa[x]=last; if(l<=mid-1) build(l,mid-1,child[x][0],x); if(mid+1<=r) build(mid+1,r,child[x][1],x); update(x); } void insert(int l,int r) { int x=find(root,l),y=find(root,l+1);//在l之后在l+1之前 splay(x,0); splay(y,root); for(int i=1;i<=r-l+1;i++) scanf("%d",&a[i]); build(1,r-l+1,child[child[root][1]][0],child[root][1]); update(child[root][1]); update(root); } void erase(int&x) { if(!x) return; s.push(x); fa[x]=0; key[x]=size[x]=sum[x]=tag2[x]=0; tag1[x]=inf; lm[x]=rm[x]=mx[x]=-(1<<30); erase(child[x][0]); erase(child[x][1]); x=0; } void del(int l,int r) { int x=find(root,l-1),y=find(root,r+1); splay(x,0); splay(y,root); erase(child[child[root][1]][0]); update(child[root][1]); update(root); } void makesame(int l,int r,int c) { int x=find(root,l-1),y=find(root,r+1); splay(x,0); splay(y,root); paint(child[child[root][1]][0],c);//更新儿子节点 update(child[root][1]); update(root); splay(child[child[root][1]][0],0); } void reverse(int l,int r) { int x=find(root,l-1),y=find(root,r+1); splay(x,0); splay(y,root); int b=child[child[root][1]][0]; if(b) paint(b);//更新儿子节点 splay(child[child[root][1]][0],0); } void getsum(int l,int r) { int x=find(root,l-1),y=find(root,r+1); splay(x,0); splay(y,root); printf("%d ",sum[child[child[root][1]][0]]); } void maxsum() { printf("%d ",mx[root]); } int main() { for(int i=1;i<=N;i++) tag1[i]=inf; scanf("%d%d",&n,&m); for(int i=2;i<=n+1;i++) { scanf("%d",&a[i]); } mx[1]=mx[n+2]=lm[1]=lm[n+2]=rm[1]=rm[n+2]=mx[0]= lm[0]=rm[0]=a[1]=a[n+2]=-(1<<30); int x; build(1,n+2,x,0); root=1; while(m--) { char s[10]; int pos,tot,c; scanf("%s",s); if(s[2]=='S') { scanf("%d%d",&pos,&tot); insert(pos+1,pos+tot); } if(s[2]=='L') { scanf("%d%d",&pos,&tot); del(pos+1,pos+tot); } if(s[2]=='K') { scanf("%d%d%d",&pos,&tot,&c); if(tot>0) makesame(pos+1,pos+tot,c); } if(s[2]=='V') { scanf("%d%d",&pos,&tot); reverse(pos+1,pos+tot); } if(s[2]=='T') { scanf("%d%d",&pos,&tot); getsum(pos+1,pos+tot); } if(s[2]=='X') { maxsum(); } } return 0; }