zoukankan      html  css  js  c++  java
  • 【集训第三天·疯狂训练】哦,顺带学习了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讲完大家都懂了,代码超级短,也是不想多说什么。

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










    If you live in the echo,
    your heart never beats as loud.
    如果你生活在回声里,
    你的心跳声永远不会轰鸣作响。
  • 相关阅读:
    对于HTTP过程中POST内容加密的解决方案
    电脑重启后IDEA项目中import class 报错
    前端Button点击无反应--记一次Debug经历
    plsql 中substr函数和instr函数的灵活应用
    浅谈Plsql 中inner join 和left join的使用
    Mysql查询优化
    Mysql单机安裝
    centos查看文件被哪个进程占用
    jvm垃圾收集器详解
    navicat破解
  • 原文地址:https://www.cnblogs.com/wsy01/p/6641990.html
Copyright © 2011-2022 走看看