集训第三天·疯狂训练哦,顺带学习了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 }
View Code

 

  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 }
View Code

 

  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 }
View Code

 

  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 }
View Code

 

  5.NOI2005  维修数列

  就是那道恶心的题,今天磨了好久,终于自己打出来了,代码就不贴了,恶心恶心。。

 

  在晚上8:30时,教练硬是把我们拖出去讲了manacher,很简单。。。30min讲完大家都懂了,代码超级短,也是不想多说什么。

 

  愉快的一天终于结束了,基本掌握伸展树,可以的,回去写英语阅读了!  

 

以上是关于集训第三天·疯狂训练哦,顺带学习了manacher的主要内容,如果未能解决你的问题,请参考以下文章

Java集训(算法&&面试题)第三天 (链表 & 树)

数学建模学习笔记集训十天之第三天

十一集训的第三天

Poemscape|Beta阶段第三天

Web前端学习第三天·fighting_常用的一些标签

莫烦scikit-learn学习自修第三天通用训练模型