• BZOJ 2002 弹飞绵羊


    某天全是数据结构的考试题T3

    在我学LCT之前就在轩神的博客中看到过这个归类在LCT里,所以事先知道了算法,不过这个貌似也挺明显的。(虽然分块更好写)

    考场上为了证明哇我会写LCT诶就强行打了只打过一遍的LCT,然后Debug两个小时。。。最后还一不小心交了一个没debug的版本。。

    //Twenty  debug两个小时 
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    #define lc ch[x][0]
    #define rc ch[x][1]
    using namespace std;
    const int maxn=2e5+299;
    int opt,xx,yy,zz,k[maxn],sz[maxn],p[maxn],ch[maxn][2],flip[maxn],n,m;
    inline int read(){
       int ret=0,f=1; char ch=getchar();
       while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
       if(ch=='-') f=-1,ch=getchar();
       for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
       return ret*f;
    }
    void update(int x) {sz[x]=sz[lc]+sz[rc]+1;}
    bool isroot(int x) {return (ch[p[x]][1]!=x&&ch[p[x]][0]!=x);}
    void build(int i,int x){
       k[i]=x;
       sz[i]=1;
       if(i+k[i]<=n) p[i]=i+k[i];
       else p[i]=n+1; 
    }
    void rotate(int x){
        int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
        if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
        ch[y][l]=ch[x][r]; p[ch[y][l]]=y;
        ch[x][r]=y; p[y]=x;
        update(y); update(x);
    }
    void splay(int x){
       for(;!isroot(x);rotate(x)){
        int y=p[x],z=p[y];
        if(!isroot(y)) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
       }
    }
    void access(int x){
       for(int t=0;x;x=p[t=x]){
        splay(x);
        rc=t;
        update(x);
       }
    }
    void cut(int a,int b){
       access(b);
       splay(b);
       p[ch[b][0]]=0;ch[b][0]=0;//p[a]=0; 多了假根 a不一定是左儿子 
       update(b);
    }
    int main()
    {
       freopen("bounce.in","r",stdin);
       freopen("bounce.out","w",stdout);
       n=read(); 
       for(int i=1;i<=n;i++) build(i,read());
       m=read(); sz[n+1]=1;//若将根点sz设为0  update时会出错 ,若不设根点翻转时似乎会出一些不可言喻的错 
       while(m--){
        opt=read(); xx=read();xx++;
        if(opt==1){
            access(xx);
            splay(xx);
            printf("%d
    ",sz[xx]-1);
        }
        else{
         yy=read();
         /*if(xx+k[xx]<=n&&xx+yy<=n) cut(xx+k[xx],xx);
         //else cut(n+1,xx);  //若将根Cut会出现不可言喻的错误 
         if(xx+yy<=n) p[xx]=xx+yy;
         //else p[xx]=n+1;
         else if(xx+k[xx]<=n) p[xx]=n+1;
         k[xx]=yy; */  //这个把不是假根改成是假根就错了。。。。 
          int now=min(n+1,yy+xx),last=min(k[xx]+xx,n+1);
          if(now!=last){
            cut(last,xx);
            p[xx]=now;
            k[xx]=yy;
          } 
        }
       }
       return 0;
    }
    弹飞绵羊

    另两种写法以后什么时候再来填坑把。

     -------------------------------------------------更新---------------------------------------------------

    2.分块

    第一次写这样的分块吧,之前打的分块都是乱搞一些线段树的题基本。每个点维护跳出块需要多少步和跳到的点。每次修改就暴力修改一个块内的该点前面的部分。

    //Twenty
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    using namespace std;
    const int maxn=200000+299;
    int n,m,fa[maxn],belong[maxn],nxt[maxn],step[maxn],gs,o,x,y;
    void modify(int x,int y) {
        if(belong[x]!=belong[y]) {
            nxt[x]=y;
            step[x]=1;
        }
        else {
            step[x]=step[y]+1;
            nxt[x]=nxt[y];
        }
    }
    int main() {
        scanf("%d",&n);
        for(int i=0;i<n;i++) {
            scanf("%d",&fa[i]);
            fa[i]=min(i+fa[i],n);
        }
        gs=sqrt(2*n)+1;
        for(int i=0;i<n;i++) 
            belong[i]=i/gs;
        belong[n]=-1;
        for(int i=n-1;i>=0;i--) modify(i,fa[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++) {
            scanf("%d%d",&o,&x);
            if(o==1) {
                int tp=x,ans=0;
                while(tp!=n) {
                    ans+=step[tp];
                    tp=nxt[tp];
                }
                printf("%d
    ",ans);
            }
            else {
                scanf("%d",&fa[x]);
                fa[x]=min(fa[x]+x,n);
                for(int i=x;i>=0&&belong[i]==belong[x];i--)
                    modify(i,fa[i]);
            }
        }
        return 0;
    }
    View Code

     

    ---------------------------------------------2018-3-7更新---------------------------------------

    现在看以前的博客觉得自己真的好蠢啊。。

    时隔多年来补splay维护括号序列的写法。

    看代码就能理解,没什么好说的。自底向上的splay真是奥妙重重。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    const int N=400007;
    typedef long long LL;
    using namespace std;
    int n,m;
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nx[N],to[N];
    void add(int u,int v) {
        nx[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
    }
    
    int dfs_clock,dfn[2][N],v[N];
    void dfs(int x) {
        v[dfn[0][x]=++dfs_clock]=1;
        for(int i=fir[x];i;i=nx[i]) 
            dfs(to[i]);
        v[dfn[1][x]=++dfs_clock]=-1;
    }
    
    int tot,p[N],sum[N],ch[N][2];
    #define lc ch[x][0]
    #define rc ch[x][1]
    void update(int x) { sum[x]=v[x]; if(lc) sum[x]+=sum[lc]; if(rc) sum[x]+=sum[rc]; }
    
    int build(int sz) {
        if(sz<=0) return 0;
        int ls=build(sz>>1);
        int x=++tot;
        int rs=build(sz-(sz>>1)-1);
        lc=ls; rc=rs;
        if(lc) p[lc]=x; 
        if(rc) p[rc]=x;
        update(x);
        return x;
    }
    
    void rotate(int x) {
        int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
        if(z) ch[z][y==ch[z][1]]=x; p[x]=z;
        ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
        ch[x][r]=y; p[y]=x;
        update(y); update(x); 
    }
    
    void splay(int x) {
        for(;p[x];rotate(x)) {
            int y=p[x],z=p[y];
            if(z) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
        }
    }
    
    int nxt(int x) {
        splay(x); x=rc;
        while(lc) x=lc;
        splay(x); return x;
    }
    
    int pre(int x) {
        splay(x); x=lc;
        while(rc) x=rc;
        splay(x); return x;
    }
    
    int split(int x) { //x作为左边最后一个 
        splay(x); int y=rc; 
        p[y]=rc=0;
        update(x); return y;
    }
    
    void merge(int x,int y) {
        splay(x); splay(y);
        while(rc) x=rc; splay(x);
        rc=y; p[y]=x; update(x);
    } 
    
    int main() {
        read(n);
        for(int i=1;i<=n;i++) {
            int fa; read(fa); 
            fa=min(fa+i,n+1); 
            add(fa,i);
        }
        dfs(n+1);
        int x=2*(n+1)+1,y=x+1;
        ch[x][1]=y; p[y]=x;
        ch[y][0]=build(2*(n+1));
        p[ch[y][0]]=y; tot=y; 
        update(y); update(x);
        read(m);
        while(m--) {
            int o,u,fa;
            read(o); read(u); u++;
            if(o==1) {
                int x=nxt(dfn[0][u]);
                printf("%d
    ",sum[lc]-1);
            }
            else {
                read(fa); fa=min(fa+u,n+1);
                int l=pre(dfn[0][u]);
                split(l);
                int r=split(dfn[1][u]);
                merge(l,r);
                split(dfn[0][fa]);
                merge(dfn[0][fa],dfn[1][u]);
                merge(dfn[1][u],dfn[1][fa]);
            }
        }
        return 0;
    }
    /*
    4                              
    1 2 1 1                           
    3
    1 1
    2 1 1
    1 1
    */
    View Code
  • 相关阅读:
    一起talk C栗子吧(第九十回:C语言实例--使用管道进行进程间通信三)
    集群技术(三)MySQL集群深度解析
    ZOJ 3609 Modular Inverse(扩展欧几里德)
    8,16小感
    Dagger2----一个最简单的Dagger2依赖的实现
    android:模拟水波效果的自己定义View
    SQL Server 运行计划操作符具体解释(1)——断言(Assert)
    参数类型 (实体类层)eneity或pojo 常用参数类型
    参数类型 (@Controller层)
    参数类型 (@Service层) impl
  • 原文地址:https://www.cnblogs.com/Achenchen/p/7475085.html
Copyright © 2020-2023  润新知