集训第三天·疯狂训练哦,顺带学习了manacher
Posted wsy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集训第三天·疯狂训练哦,顺带学习了manacher相关的知识,希望对你有一定的参考价值。
虽然说是疯狂训练吧,但是也没写多少题,就把伸展树的操作熟悉了一下,ac了5个题目。
一整天没啥可吐槽的,除了昨天在机房打游戏的某位朋友翻车后和教练谈了谈心2333
说题吧。。
1.BZOJ1208 HNOI2004 宠物收养所
这个题思路很简单,当做模板题打,在模板题中也算是简单的了,涉及操作:前驱,后继,插入,删除。。输入进来就插入,领养走就删除,并没有什么可说的。加上一个标记表示现在树上表示的是宠物还是人。
另外听说可以用set做,但是我并不会set(???set都不会吃屎吧)。
CODE:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n,size,rt,kind,t1,t2; 5 long long ans; 6 int tr[80001][2],num[80001],fa[80001]; 7 void rotate(int x,int &k) 8 { 9 int y=fa[x],z=fa[y],l,r; 10 if(tr[y][0]==x)l=0;else l=1;r=l^1; 11 if(y==k)k=x; 12 else{if(tr[z][0]==y)tr[z][0]=x;else tr[z][1]=x;} 13 fa[x]=z;fa[y]=x;fa[tr[x][r]]=y; 14 tr[y][l]=tr[x][r];tr[x][r]=y; 15 } 16 void splay(int x,int &k) 17 { 18 int y,z; 19 while(x!=k) 20 { 21 y=fa[x],z=fa[y]; 22 if(y!=k) 23 { 24 if((tr[y][0]==x)^(tr[z][0]==y))rotate(x,k); 25 else rotate(y,k); 26 } 27 rotate(x,k); 28 } 29 } 30 void ins(int &k,int x,int last) 31 { 32 if(k==0){size++;k=size;num[k]=x;fa[k]=last;splay(k,rt);return;} 33 if(x<num[k])ins(tr[k][0],x,k);else ins(tr[k][1],x,k); 34 } 35 void del(int x) 36 { 37 splay(x,rt); 38 if(tr[x][0]*tr[x][1]==0) 39 {rt=tr[x][0]+tr[x][1];} 40 else 41 { 42 int k=tr[x][1]; 43 while(tr[k][0])k=tr[k][0]; 44 tr[k][0]=tr[x][0];fa[tr[x][0]]=k; 45 rt=tr[x][1]; 46 } 47 fa[rt]=0; 48 } 49 void ask_before(int k,int x) 50 { 51 if(k==0)return; 52 if(num[k]<=x){t1=k;ask_before(tr[k][1],x);} 53 else ask_before(tr[k][0],x); 54 } 55 void ask_after(int k,int x) 56 { 57 if(k==0)return; 58 if(num[k]>=x){t2=k;ask_after(tr[k][0],x);} 59 else ask_after(tr[k][1],x); 60 } 61 62 int main() 63 { 64 scanf("%d",&n); 65 int f,x; 66 for(int i=1;i<=n;i++) 67 { 68 scanf("%d%d",&f,&x); 69 if(!rt){kind=f;ins(rt,x,0);} 70 else if(kind==f){ins(rt,x,0);} 71 else 72 { 73 t1=t2=-1; 74 ask_before(rt,x);ask_after(rt,x); 75 if(t1==-1){ans+=num[t2]-x;ans%=1000000;del(t2);} 76 else if(t2==-1){ans+=x-num[t1];ans%=1000000;del(t1);} 77 else 78 { 79 if(x-num[t1]>num[t2]-x) {ans+=num[t2]-x;ans%=1000000;del(t2);} 80 else{ans+=x-num[t1];ans%=1000000;del(t1);} 81 } 82 } 83 } 84 cout<<ans<<endl; 85 return 0; 86 }
2.codevs1296 营业额统计
和前面一题类似,操作基本一样。
找出前驱后继,比较它们和当天营业额的差值,取小的那个给答案加上,完美。。
PS:前驱和后继初值赋值为正无穷或负无穷,以免找不到前驱/后继而成为 abs(0-当天营业额),影响答案取值。
CODE:
1 #include<bits/stdc++.h> 2 #define N 32769 3 using namespace std; 4 int c[N][2],val[N],fa[N],tot,ans,n,rt,a,t1,t2; 5 int read(){ 6 char c;int f=1,x=0;c=getchar(); 7 while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} 8 while(c<=‘9‘&&c>=‘0‘)x=x*10+c-‘0‘,c=getchar(); 9 return f*x; 10 } 11 12 void rotate(int x,int &k){ 13 int y=fa[x],z=fa[y],l,r; 14 if(c[y][0]==x)l=0;else l=1;r=l^1; 15 if(y==k)k=x; 16 else c[z][c[z][1]==y]=x; 17 fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 18 c[y][l]=c[x][r];c[x][r]=y; 19 } 20 21 void splay(int x,int &k){ 22 while(x!=k){ 23 int y=fa[x],z=fa[y]; 24 if(y!=k){ 25 if((c[y][0]==x)^(c[z][0]==y))rotate(x,k); 26 else rotate(y,k); 27 } 28 rotate(x,k); 29 } 30 } 31 32 void insert(int x){ 33 if(!rt){ 34 rt=++tot; 35 val[tot]=a; 36 return; 37 } 38 int p=rt,z; 39 while(p){ 40 z=p; 41 if(a>=val[p])p=c[p][1]; 42 else p=c[p][0]; 43 } 44 if(a>=val[z])c[z][1]=++tot; 45 else c[z][0]=++tot; 46 val[tot]=a;fa[tot]=z; 47 splay(tot,rt); 48 } 49 50 void ask_before(int x){ 51 if(x==0)return; 52 if(val[x]==a){t1=a;return;} 53 if(a>val[x]){t1=val[x];ask_before(c[x][1]);} 54 else ask_before(c[x][0]); 55 } 56 57 void ask_after(int x){ 58 if(x==0)return; 59 if(val[x]==a){t2=a;return;} 60 if(a<val[x]){t2=val[x];ask_after(c[x][0]);} 61 else ask_after(c[x][1]); 62 } 63 64 int main(){ 65 scanf("%d",&n); 66 for(int i=1;i<=n;i++){ 67 a=read(); 68 t1=t2=99999999; 69 ask_before(rt);ask_after(rt); 70 if(i==1)ans+=a; 71 else ans+=min(abs(t1-a),abs(t2-a)); 72 insert(rt); 73 } 74 printf("%d",ans); 75 return 0; 76 }
3.codevs1286 NOI2004郁闷的营销员
大致思路:伸展树基本操作+巧妙的整体修改
原本以为使用区间操作,但发现可以把原有人的工资增减变为所有人(包括增减工资后加的人)的增减。只用记录一个all ,然后插入新成员时减去all的值就行。
PS:关于下面那个splay操作,其实是可有可无的,只是优化了时间而已。若是懒,可以不打splay和rotate,BZOJ时间限制5s,一样可以水过,但codevs时间限制1s,要TLE几组
至于splay优化时间的原因:如果构成了一条长链(超级长,可近似看做一个O(n)的序列),通过splay可以把它的深度减小,变为一棵二叉树
CODE:
1 #include<bits/stdc++.h> 2 #define N 32769 3 using namespace std; 4 int c[N][2],val[N],fa[N],tot,ans,n,rt,a,t1,t2; 5 int read(){ 6 char c;int f=1,x=0;c=getchar(); 7 while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} 8 while(c<=‘9‘&&c>=‘0‘)x=x*10+c-‘0‘,c=getchar(); 9 return f*x; 10 } 11 12 void rotate(int x,int &k){ 13 int y=fa[x],z=fa[y],l,r; 14 if(c[y][0]==x)l=0;else l=1;r=l^1; 15 if(y==k)k=x; 16 else c[z][c[z][1]==y]=x; 17 fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 18 c[y][l]=c[x][r];c[x][r]=y; 19 } 20 21 void splay(int x,int &k){ 22 while(x!=k){ 23 int y=fa[x],z=fa[y]; 24 if(y!=k){ 25 if((c[y][0]==x)^(c[z][0]==y))rotate(x,k); 26 else rotate(y,k); 27 } 28 rotate(x,k); 29 } 30 } 31 32 void insert(int x){ 33 if(!rt){ 34 rt=++tot; 35 val[tot]=a; 36 return; 37 } 38 int p=rt,z; 39 while(p){ 40 z=p; 41 if(a>=val[p])p=c[p][1]; 42 else p=c[p][0]; 43 } 44 if(a>=val[z])c[z][1]=++tot; 45 else c[z][0]=++tot; 46 val[tot]=a;fa[tot]=z; 47 splay(tot,rt); 48 } 49 50 void ask_before(int x){ 51 if(x==0)return; 52 if(val[x]==a){t1=a;return;} 53 if(a>val[x]){t1=val[x];ask_before(c[x][1]);} 54 else ask_before(c[x][0]); 55 } 56 57 void ask_after(int x){ 58 if(x==0)return; 59 if(val[x]==a){t2=a;return;} 60 if(a<val[x]){t2=val[x];ask_after(c[x][0]);} 61 else ask_after(c[x][1]); 62 } 63 64 int main(){ 65 scanf("%d",&n); 66 for(int i=1;i<=n;i++){ 67 a=read(); 68 t1=t2=99999999; 69 ask_before(rt);ask_after(rt); 70 if(i==1)ans+=a; 71 else ans+=min(abs(t1-a),abs(t2-a)); 72 insert(rt); 73 } 74 printf("%d",ans); 75 return 0; 76 }
4.codevs3303 翻转区间
就是一个模板题啊,多次翻转区间,加上lazy标记就好
CODE:
1 #include<bits/stdc++.h> 2 #define N 100005 3 using namespace std; 4 int c[N][2],fa[N],a[N],size[N],rev[N],rt,n,m; 5 int read(){ 6 char c;int f=1,x=0;c=getchar(); 7 while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} 8 while(c<=‘9‘&&c>=‘0‘)x=x*10+c-‘0‘,c=getchar(); 9 return f*x; 10 } 11 12 void update(int x){ 13 int l=c[x][0],r=c[x][1]; 14 size[x]=size[l]+size[r]+1; 15 } 16 17 void pushdown(int x){ 18 if(rev[x]){ 19 swap(c[x][0],c[x][1]);rev[x]=0; 20 rev[c[x][0]]^=1;rev[c[x][1]]^=1; 21 } 22 } 23 24 void rotate(int x,int &k){ 25 int y=fa[x],z=fa[y],l,r; 26 if(c[y][0]==x)l=0;else l=1;r=l^1; 27 if(y==k)k=x; 28 else c[z][c[z][1]==y]=x; 29 fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 30 c[y][l]=c[x][r];c[x][r]=y; 31 update(y);update(x); 32 } 33 34 void splay(int x,int &k){ 35 while(x!=k){ 36 int y=fa[x],z=fa[y]; 37 if(y!=k){ 38 if(c[y][0]==x^c[z][0]==y)rotate(x,k); 39 else rotate(y,k); 40 } 41 rotate(x,k); 42 } 43 } 44 45 void build(int l,int r,int f){ 46 if(l>r)return; 47 if(l==r){ 48 size[l]=1;fa[l]=f; 49 if(l>f)c[f][1]=l; 50 else c[f][0]=l; 51 return; 52 } 53 int mid=(l+r)>>1; 54 build(l,mid-1,mid);build(mid+1,r,mid); 55 update(mid);fa[mid]=f;c[f][mid>f]=mid; 56 } 57 58 int find(int x,int k){ 59 pushdown(x); 60 int l=c[x][0],r=c[x][1]; 61 if(size[l]+1==k)return x; 62 if(size[l]+1>k)return find(l,k); 63 return find(r,k-1-size[l]); 64 } 65 66 int main(){ 67 n=read();m=read(); 68 for(int i=1;i<=n+2;i++)a[i]=i; 69 build(1,n+2,0);rt=(3+n)>>1; 70 int x,y; 71 for(int i=1;i<=m;i++){ 72 x=read(),y=read(); 73 int l=find(rt,x),r=find(rt,y+2); 74 splay(l,rt);splay(r,c[l][1]); 75 rev[c[r][0]]^=1; 76 } 77 for(int i=2;i<=n+1;i++) 78 printf("%d ",find(rt,i)-1); 79 80 return 0; 81 }
5.NOI2005 维修数列
就是那道恶心的题,今天磨了好久,终于自己打出来了,代码就不贴了,恶心恶心。。
在晚上8:30时,教练硬是把我们拖出去讲了manacher,很简单。。。30min讲完大家都懂了,代码超级短,也是不想多说什么。
愉快的一天终于结束了,基本掌握伸展树,可以的,回去写英语阅读了!
以上是关于集训第三天·疯狂训练哦,顺带学习了manacher的主要内容,如果未能解决你的问题,请参考以下文章