要求维护一个数列,支持以上几种操作。
此题可以看作平衡树的一个大模板,由于是区间问题,所以用splay或者fhqtreap,我用了fhqtreap(写起来太舒服了)。
数据范围:
你可以认为在任何时刻,数列中至少有 1 个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有 30 000 个数;
100%的数据中,任何时刻数列中最多含有 500 000 个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。
1.插入和删除tot个数:因为这题时间卡的很紧,所以不能使用比较方便的那种O(nlogn)方式插入,因为此题是区间,所以插入的数据必是单调插入,所以此处使用笛卡尔树的建树方式,复杂度为O(n),因为需要用到栈,此处建议手写栈,STL太慢了(STL一生黑QAQ,真香)。这题还得用读入优化,不知是 。删除的话直接将区间提取出来删掉就可以了。但是,此处有个问题,删除的空间需要回收,因为只有128M内存,貌似最多也就开1e6,但是,数据范围告诉了数列中最多有5e5个数字,所以删除的时候就要求空间回收,下次插入的时候要插到这些空间中(再来个栈就完事了,小问题)。
2.修改和反转:像线段树一样就好了,打个标记,然后再访问的时候往下推。
3.求和求最大子序列,维护sum,lmax,rmax,mmax就行了。(%%%)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX=5e5+20,INF=0x7fffffff; 4 struct ppp{ 5 int val,ch[2],rnd,sum,lmax,rmax,mmax,size; 6 int change,reverse; 7 }treap[MAX]; 8 int n,m,tot,root,name[MAX],st[MAX]; 9 int read() 10 { 11 int tmp=0,fh=1; char c=getchar(); 12 while ((c<'0'||c>'9')&&c!='-') c=getchar(); 13 if (c=='-') fh=-1,c=getchar(); 14 while (c>='0'&&c<='9') tmp=tmp*10+c-48,c=getchar(); 15 return tmp*fh; 16 } 17 inline int NEW(int val) 18 { 19 int p=name[tot--]; 20 treap[p]=(ppp){val,0,0,rand(),0,0,0,0,0,0,0}; 21 treap[p].val=val; 22 treap[p].rnd=rand(); 23 treap[p].sum=val; 24 treap[p].lmax=treap[p].rmax=treap[p].mmax=val; 25 treap[p].size=1; 26 treap[p].change=INF; 27 return p; 28 } 29 inline void reuse(int p) 30 { 31 if(!p) return ; 32 name[++tot]=p; 33 reuse(treap[p].ch[0]); 34 reuse(treap[p].ch[1]); 35 } 36 inline void down(int p) 37 { 38 if(p==0) return; 39 if(treap[p].reverse) 40 { 41 treap[p].reverse=0; 42 swap(treap[p].ch[1],treap[p].ch[0]); 43 treap[treap[p].ch[0]].reverse^=1; 44 treap[treap[p].ch[1]].reverse^=1; 45 swap(treap[p].lmax,treap[p].rmax); 46 } 47 if(treap[p].change!=INF) 48 { 49 int k=treap[p].change; 50 treap[p].change=INF; 51 treap[p].rmax=treap[p].mmax=treap[p].lmax=(k>=0? k*treap[p].size:k); 52 treap[p].sum=treap[p].size*k; 53 treap[p].val=k; 54 treap[treap[p].ch[0]].change=k; 55 treap[treap[p].ch[1]].change=k; 56 } 57 } 58 inline void update(int p) 59 { 60 down(treap[p].ch[0]); 61 down(treap[p].ch[1]); 62 treap[p].sum=treap[p].val+treap[treap[p].ch[0]].sum+treap[treap[p].ch[1]].sum; 63 treap[p].size=treap[treap[p].ch[0]].size+treap[treap[p].ch[1]].size+1; 64 treap[p].lmax=max(treap[treap[p].ch[0]].lmax,treap[treap[p].ch[0]].sum+treap[p].val+max(0,treap[treap[p].ch[1]].lmax)); 65 treap[p].rmax=max(treap[treap[p].ch[1]].rmax,treap[treap[p].ch[1]].sum+treap[p].val+max(0,treap[treap[p].ch[0]].rmax)); 66 treap[p].mmax=max(max(treap[treap[p].ch[0]].mmax,treap[treap[p].ch[1]].mmax),treap[p].val+max(0,treap[treap[p].ch[0]].rmax)+max(0,treap[treap[p].ch[1]].lmax)); 67 } 68 69 inline int build(int k)//笛卡尔树的建树方式 按照权值升序插入 O(n) 70 { 71 int tem_root,top=0; 72 tem_root=read(); 73 tem_root=NEW(tem_root); 74 st[++top]=tem_root; 75 for(int i=1;i<k;i++)//k-1 次循环 76 { 77 int val; 78 val=read(); 79 int p=NEW(val),last=0; 80 while(top and treap[st[top]].rnd>treap[p].rnd)//小根堆 81 { 82 treap[p].ch[0]=st[top]; 83 update(st[top]); 84 top--; 85 } 86 if(top) 87 treap[st[top]].ch[1]=p; 88 else 89 tem_root=p; 90 st[++top]=p; 91 update(p); 92 } 93 while(top) 94 { 95 update(st[top]); 96 top--; 97 } 98 return tem_root; 99 } 100 inline void split(int now,int &x,int &y,int rank) 101 { 102 down(now); 103 if(rank>=treap[now].size) 104 { 105 x=now,y=0; 106 return ; 107 } 108 if(rank<=0) 109 { 110 y=now,x=0; 111 return ; 112 } 113 if(rank<=treap[treap[now].ch[0]].size) 114 { 115 y=now; 116 split(treap[now].ch[0],x,treap[now].ch[0],rank); 117 } 118 else 119 { 120 x=now; 121 split(treap[now].ch[1],treap[now].ch[1],y,rank-treap[treap[now].ch[0]].size-1); 122 } 123 update(now); 124 } 125 inline int merge(int x,int y) 126 { 127 down(x);down(y); 128 if(x==0 or y==0) 129 return x+y; 130 if(treap[x].rnd<treap[y].rnd) 131 { 132 treap[x].ch[1]=merge(treap[x].ch[1],y); 133 update(x); 134 update(treap[x].ch[1]); 135 return x; 136 } 137 else 138 { 139 treap[y].ch[0]=merge(x,treap[y].ch[0]); 140 update(y); 141 update(treap[y].ch[0]); 142 return y; 143 } 144 } 145 inline void remove(int pos,int num) 146 { 147 int x=0,y=0,z=0; 148 split(root,x,y,pos-1); 149 split(y,y,z,num); 150 reuse(y); 151 root=merge(x,z); 152 } 153 inline void insert(int pos,int num) 154 { 155 int x,y,z; 156 split(root,x,y,pos); 157 z=build(num); 158 root=merge(merge(x,z),y); 159 } 160 inline void make_same(int pos,int num,int c) 161 { 162 int x=0,y=0,z=0; 163 split(root,x,y,pos-1); 164 split(y,y,z,num); 165 treap[y].change=c; 166 y=merge(y,z); 167 root=merge(x,y); 168 } 169 inline void reverse(int pos,int num) 170 { 171 int x=0,y=0,z=0; 172 split(root,x,y,pos-1); 173 split(y,y,z,num); 174 treap[y].reverse^=1; 175 y=merge(y,z); 176 root=merge(x,y); 177 } 178 inline void getsum(int pos,int sum) 179 { 180 int x=0,y=0,z=0; 181 split(root,x,y,pos-1); 182 split(y,y,z,sum); 183 printf("%d\n",treap[y].sum); 184 y=merge(y,z); 185 root=merge(x,y); 186 } 187 inline void maxsum() 188 { 189 printf("%d\n",treap[root].mmax); 190 } 191 int main() 192 { 193 //scanf("%d%d",&n,&m); 194 n=read();m=read(); 195 for (int i=500010;i;i--) name[++tot]=i; 196 treap[0].lmax=treap[0].rmax=treap[0].mmax=-INF; 197 root=build(n); 198 char opt[15]; 199 for(int i=1;i<=m;i++) 200 { 201 char c=getchar(); 202 while(c<'A' or c>'Z') c=getchar(); 203 opt[0]=c;opt[1]=getchar();opt[2]=getchar(); 204 while((c>='A' and c<='Z') or c=='-') c=getchar(); 205 if(opt[0]=='I') 206 { 207 int k=read(),jkl=read(); 208 //scanf("%d%d",&k,&jkl); 209 insert(k,jkl); 210 } 211 else if(opt[0]=='D') 212 { 213 int O=read(),P=read(); 214 //scanf("%d%d",&O,&P); 215 remove(O,P); 216 } 217 else if(opt[2]=='K') 218 { 219 int O=read(),P=read(),C=read(); 220 //scanf("%d%d%d",&O,&P,&C); 221 make_same(O,P,C); 222 } 223 else if(opt[0]=='R') 224 { 225 int O=read(),P=read(); 226 //scanf("%d%d",&O,&P); 227 reverse(O,P); 228 } 229 else if(opt[0]=='G') 230 { 231 int O=read(),P=read(); 232 //scanf("%d%d",&O,&P); 233 getsum(O,P); 234 } 235 else 236 maxsum(); 237 } 238 return 0; 239 }