[bzoj1500 维修数列](NOI2005) (splay)
真的是太弱了TAT。。。光是把代码码出来就花了3h。。还调了快1h才弄完T_T
号称考你会不会splay(当然通过条件是1h内AC。。吓傻)。。。
黄学长的题解:http://hzwer.com/2841.html
当然了蒟蒻的splay模板全部都是借(抄)鉴(袭)黄学长的。。。。
主要是注意任何对子树的修改一定要记得pushup一定要记得pushup一定要记得pushup。。。计算最大子段和和bzoj1858一个姿势,就是维护子树的最大子段和,从左和从右开始的最大子段和(当然了平衡树和线段树在这里还是有点区别的);
对于修改和翻转可以打懒标记。。。插入的话可以先把要插入的数建出一颗splay树,然后把新树和原来的树连起来;
为了避免判断区间边界啊什么的可以多建两个边界节点。。。
据说要加上垃圾回收,这样的话还要新开一个id数组用来存节点的编号,那样的话数组开到50w就可以了。。
如果不要垃圾回收的话,删除时把对应区间的子树与原来的树断开连接就好了,垃圾回收还得把要砍掉的子树里面的节点遍历重置。。。oj上没写数据范围让人感觉有点虚。。
1 #include<stdio.h> 2 #include<math.h> 3 #include<queue> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 const int inf=1002333333; 8 const int maxn=500233;//题目又没说数据范围= =//经测试加了垃圾优化开50w就好了= = 9 struct zs{ 10 int c[2],fa,mx,lmx,rmx,val,size,sum; 11 bool change,rev; 12 }tree[maxn]; 13 queue<int>q; 14 int a[maxn],id[maxn]; 15 char iid[23]; 16 int i,j,k,n,m,cnt,tot,x,c,root; 17 void update(int now){ 18 int l=tree[now].c[0],r=tree[now].c[1]; 19 tree[now].size=tree[l].size+tree[r].size+1; 20 tree[now].sum=tree[l].sum+tree[r].sum+tree[now].val; 21 tree[now].mx=max(tree[l].mx,tree[r].mx); 22 tree[now].mx=max(tree[now].mx,tree[l].rmx+tree[now].val+tree[r].lmx); 23 tree[now].lmx=max(tree[l].lmx,tree[l].sum+tree[now].val+tree[r].lmx); 24 tree[now].rmx=max(tree[r].rmx,tree[r].sum+tree[now].val+tree[l].rmx); 25 } 26 void deal(int now,bool change,bool rev,int val){ 27 if(change){ 28 tree[now].change=1; 29 tree[now].val=val; 30 tree[now].sum=tree[now].size*val; 31 if(val>0) 32 tree[now].mx=tree[now].lmx=tree[now].rmx=tree[now].sum; 33 else tree[now].mx=val,tree[now].lmx=tree[now].rmx=0; 34 } 35 else//如果整段覆盖了翻不翻转都一样 36 if(rev){ 37 tree[now].rev^=1; 38 // printf("! %d %d %d\n",now,tree[now].c[0],tree[now].c[1]); 39 swap(tree[now].c[0],tree[now].c[1]); 40 swap(tree[now].lmx,tree[now].rmx); 41 } 42 } 43 void pushdown(int now){ 44 int l=tree[now].c[0],r=tree[now].c[1]; 45 if(l)deal(l,tree[now].change,tree[now].rev,tree[now].val); 46 if(r)deal(r,tree[now].change,tree[now].rev,tree[now].val); 47 tree[now].change=tree[now].rev=0; 48 } 49 void build(int l,int r,int premid){ 50 int now,mid,fa; 51 if(l>r)return; 52 mid=(l+r)>>1; 53 fa=id[premid];now=id[mid];//本来id[i]==i,但因为垃圾回收。。。 54 if(mid<premid)tree[fa].c[0]=now;else tree[fa].c[1]=now; 55 tree[now].fa=fa; 56 tree[now].val=a[mid]; 57 if(l<r){ 58 build(l,mid-1,mid);build(mid+1,r,mid); 59 update(now); 60 }else{ 61 // printf(" !%d %d\n",now,tree[now].val); 62 tree[now].size=1; 63 tree[now].mx=tree[now].sum=tree[now].val; 64 if(tree[now].val>0)tree[now].lmx=tree[now].rmx=tree[now].mx; 65 else tree[now].lmx=tree[now].rmx=0; 66 } 67 // printf("! %d %d %d %d %d %d %d %d\n",now,tree[now].c[0],tree[now].c[1],tree[now].mx,tree[now].lmx,tree[now].rmx,tree[now].change,tree[now].rev); 68 } 69 void rotate(int now,int&root){ 70 int fa,gfa,l,r; 71 fa=tree[now].fa;gfa=tree[fa].fa; 72 if(fa==root)root=now; 73 else tree[gfa].c[tree[gfa].c[0]!=fa]=now; 74 if(tree[fa].c[0]==now)l=0;else l=1; 75 r=l^1; 76 tree[now].fa=gfa;tree[fa].fa=now; 77 tree[fa].c[l]=tree[now].c[r];tree[now].c[r]=fa; 78 tree[tree[fa].c[l]].fa=fa; 79 update(fa);update(now); 80 } 81 void splay(int now,int&root){ 82 int fa,gfa; 83 while(now!=root){ 84 fa=tree[now].fa;gfa=tree[fa].fa; 85 if(fa!=root) 86 if((tree[fa].c[0]==now)^(tree[gfa].c[0]==fa))rotate(now,root); 87 else rotate(fa,root); 88 rotate(now,root); 89 } 90 } 91 int find(int now,int k){ 92 if(tree[now].change||tree[now].rev)pushdown(now); 93 int l=tree[now].c[0]; 94 if(k<=tree[l].size)return find(l,k); 95 else if(k==tree[l].size+1)return now; 96 else return find(tree[now].c[1],k-tree[l].size-1); 97 } 98 void ins(int pos,int tot){ 99 // int now=find(root,pos+1); 100 for(int i=1;i<=tot;i++)scanf("%d",&a[i]); 101 for(int i=1;i<=tot;i++) 102 if(!q.empty())id[i]=q.front(),q.pop(); 103 else id[i]=++cnt; 104 int troot=id[(tot+1)>>1]; 105 build(1,tot,0); 106 int x=find(root,pos+1),y=find(root,pos+2); 107 splay(x,root);splay(y,tree[x].c[1]); 108 tree[y].c[0]=troot;tree[troot].fa=y; 109 update(y);update(x); 110 // printf(" !%d\n",root); 111 } 112 void recover(int &now){ 113 tree[now].fa=0; 114 if(tree[now].c[0])recover(tree[now].c[0]); 115 if(tree[now].c[1])recover(tree[now].c[1]); 116 q.push(now); 117 tree[now].change=tree[now].rev=0; 118 now=0; 119 } 120 void del(int pos,int tot){ 121 // int now=find(root,pos+1); 122 int x=find(root,pos),y=find(root,pos+tot+1); 123 splay(x,root);splay(y,tree[x].c[1]); 124 // int z=tree[y].c[0];tree[y].c[0]=0; 125 recover(tree[y].c[0]); 126 update(y);update(x);//要更新祖先TAT 127 } 128 void bilibili(int pos,int tot,int change,int rev,int val){//处理修改&&翻转 129 int x=find(root,pos),y=find(root,pos+tot+1); 130 splay(x,root);splay(y,tree[x].c[1]); 131 // printf(" ! %d %d %d %d\n",tree[y].c[0],change,rev,val); 132 deal(tree[y].c[0],change,rev,val); 133 update(y);update(x);//也要更新祖先TAT 134 // printf("! %d %d\n",y,x); 135 } 136 void getsum(int pos,int tot){ 137 // int now=find(root,pos+1); 138 int x=find(root,pos),y=find(root,pos+tot+1); 139 splay(x,root);splay(y,tree[x].c[1]); 140 int z=tree[y].c[0]; 141 printf("%d\n",tree[z].sum); 142 } 143 int main(){ 144 scanf("%d%d",&n,&m); 145 for(i=1;i<=n;i++)scanf("%d",&a[i+1]); 146 a[1]=a[n+2]=-inf; 147 for(i=1;i<=n+2;i++)id[i]=i; 148 tree[0].mx=-inf; 149 root=(n+2+1)>>1;cnt=n+2; 150 build(1,n+2,0); 151 // for(i=1;i<=cnt;i++)printf(" %d %d %d %d %d %d\n",i,tree[i].c[0],tree[i].c[1],tree[i].mx,tree[i].lmx,tree[i].rmx); 152 for(i=1;i<=m;i++){ 153 scanf("%s",iid); 154 if(iid[2]=='S')scanf("%d%d",&x,&tot),ins(x,tot); 155 else if(iid[2]=='L')scanf("%d%d",&x,&tot),del(x,tot); 156 else if(iid[2]=='K')scanf("%d%d%d",&x,&tot,&c),bilibili(x,tot,1,0,c); 157 else if(iid[2]=='V')scanf("%d%d",&x,&tot),bilibili(x,tot,0,1,0); 158 else if(iid[2]=='T')scanf("%d%d",&x,&tot),getsum(x,tot); 159 else if(iid[2]=='X')printf("%d\n",tree[root].mx); 160 //if(i==4) 161 // for(int i=1;i<=cnt;i++)printf(" %d %d %d %d %d %d %d %d\n",i,tree[i].c[0],tree[i].c[1],tree[i].mx,tree[i].lmx,tree[i].rmx,tree[i].change,tree[i].rev); 162 // return 233; 163 } 164 return 0; 165 }
//连续几天写到的题目都没有数据范围是什么鬼。。。
//至于读入的时候少打一个%d这种错显然只有傻叉才会犯的啊TAT
//变量名太长的悲剧。。。把几个过程缩成一个结果代码量还是别人的两倍T_T
感觉自己还不会splay。。。果然是太弱了。。也许过一阵子再来写这题效果会好点= =
2015.8.1:4h
2015.8.6:2h : 注意删点的时候那些新建节点时没有初始化的信息都要初始化,
2016.1.6:4h+。。TAT。。太久没玩懒标记结果卡了一晚上+一节电脑课。。。要好好想一下什么时候更新本节点的信息。。