zoukankan      html  css  js  c++  java
  • bzoj 3123 可持久化线段树启发式合并

      首先没有连边的操作的时候,我们可以用可持久化线段树来维护这棵树的信息,建立权值可持久化线段树,那么每个点继承父节点的线段树,当询问为x,y的时候我们可以询问rot[x]+rot[y]-rot[lca(x,y)]-rot[lca(x,y)->father]这棵树来得知这个链的信息。

      那么对于连边操作,相当于合并两棵树,我们可以将树的节点数小的树全部拆掉连到节点大的树中,这样每个点最多会被操作logn次,每次操作的时间复杂度为logn,所以是mlog^2n的。

      反思:对于树的连通性我是用并查集维护的,对于合并操作还需要dfs一次小的树来维护各种信息,但是忘记对x,y点连边了,导致一直RE.(RE是因为某次值不正确,导致下一次^的点超过n)。

         各种慢= =。

    /**************************************************************
        Problem: 3123
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:16612 ms
        Memory:81512 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 100010
    #define maxm 200010
     
    using namespace std;
     
    struct rec {
        int key,num;
        rec() {
            key=num=0;
        }
    }a[maxn];
     
    struct segment {
        int left,right,cnt;
        int son[2];
        segment() {
            left=right=cnt=0;
            memset(son,0,sizeof son);
        }
    }t[maxn<<5];
     
    int n,m,l,N,tot;
    int pre[maxm<<1],last[maxm<<1],other[maxm<<1];
    int ans[maxn],rot[maxn];
    int dep[maxn],jump[maxn][20],father[maxn],size[maxn],que[maxn];
     
    void connect(int x,int y) {
        pre[++l]=last[x];
        last[x]=l;
        other[l]=y;
    }
     
    int getfather(int x) {
        if (father[x]==x) return x;
        return father[x]=getfather(father[x]);
    }
     
    void dfs(int x,int fa) {
        jump[x][0]=fa; dep[x]=dep[fa]+1;
        for (int p=last[x];p;p=pre[p]) {
            if (other[p]==fa) continue;
            dfs(other[p],x);
        }
    }
     
    bool cmp1(rec x,rec y) {
        return x.key<y.key;
    }
     
    bool cmp2(rec x,rec y) {
        return x.num<y.num;
    }
     
    int lca(int x,int y) {
        if (dep[x]>dep[y]) swap(x,y);
        int d=dep[y]-dep[x];
        for (int i=0;i<=16;i++) if (d&(1<<i)) y=jump[y][i];
        if (x==y) return x;
        for (int i=16;i>=0;i--) if (jump[x][i]!=jump[y][i]) x=jump[x][i],y=jump[y][i];
        return jump[x][0];
    }
     
    void build(int &x,int l,int r) {
        if (!x) x=++tot;
        t[x].left=l; t[x].right=r;
        if (t[x].left==t[x].right) return ;
        int mid=t[x].left+t[x].right>>1;
        build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r);
    }
     
    void insert(int &x,int rot,int key) {
        if (!x) x=++tot;
        t[x].left=t[rot].left; t[x].right=t[rot].right;
        if (t[x].left==t[x].right) {
            t[x].cnt=t[rot].cnt+1;
            return ;
        }
        int mid=t[x].left+t[x].right>>1;
        if (key>mid) {
            t[x].son[0]=t[rot].son[0];
            insert(t[x].son[1],t[rot].son[1],key);
        } else {
            t[x].son[1]=t[rot].son[1];
            insert(t[x].son[0],t[rot].son[0],key);
        }
        t[x].cnt=t[rot].cnt+1;
    }
     
    int query(int x,int y,int l1,int l2,int k) {
        //printf("%d %d %d ",x,t[x].left,t[x].right);
        if (t[x].left==t[x].right) return t[x].left;
        int cur=t[t[x].son[0]].cnt+t[t[y].son[0]].cnt-t[t[l1].son[0]].cnt-t[t[l2].son[0]].cnt;
        //printf("%d
    ",cur);
        if (k>cur) return query(t[x].son[1],t[y].son[1],t[l1].son[1],t[l2].son[1],k-cur); else
            return query(t[x].son[0],t[y].son[0],t[l1].son[0],t[l2].son[0],k);
    }
     
    void make(int x,int fa) {
        insert(rot[x],rot[fa],a[x].key);
        for (int p=last[x];p;p=pre[p]) {
            if (other[p]==fa) continue;
            make(other[p],x);
        }
    }
     
    void update(int x,int fa,int j) {
        jump[x][j]=jump[jump[x][j-1]][j-1];
        for (int p=last[x];p;p=pre[p]) {
            if (other[p]==fa) continue;
            update(other[p],x,j);
        }
    }
     
    void merge(int x,int y) {
        int fx=getfather(x),fy=getfather(y);
        //if (x==1) printf("%d %d
    ",fx,fy);
        if (size[fx]<size[fy]) swap(x,y);
        fx=getfather(x),fy=getfather(y);
        father[fy]=fx; size[fx]+=size[fy];
        dfs(y,x); make(y,x); 
        for (int i=1;i<=16;i++) update(y,x,i);
        //for (int i=1;i<=n;i++) printf("%d %d
    ",i,jump[i][0]);
    }
     
    int main() {
        //freopen("3123.in","r",stdin); freopen("3123.out","w",stdout);
        int task; scanf("%d",&task);
        scanf("%d%d%d",&n,&m,&task);
        for (int i=1;i<=n;i++) scanf("%d",&a[a[i].num=i].key); 
     
        sort(a+1,a+1+n,cmp1);
        int cur; ans[1]=cur=a[1].key;
        for (int i=1,j=1;i<=n;i++) 
            if (a[i].key==cur) a[i].key=j; else ans[++j]=cur=a[i].key,a[i].key=j,N=j;
        sort(a+1,a+1+n,cmp2);
        //for (int i=1;i<=n;i++) printf("%d ",ans[i]); printf("
    ");
        //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("
    ");
         
        for (int i=1;i<=n;i++) father[i]=i,size[i]=1;
        for (int i=1;i<=m;i++) {
            int x,y; scanf("%d%d",&x,&y);
            connect(x,y); connect(y,x);
            int fx=getfather(x),fy=getfather(y);
            father[fx]=fy; size[fy]+=size[fx];
        }
        for (int i=1;i<=n;i++) if (!jump[i][0]) dfs(i,0);
        //for (int i=1;i<=n;i++) printf("%d %d
    ",i,father[i]);
        //for (int i=1;i<=n;i++) if (i==getfather(i)) printf("%d %d
    ",i,size[i]);
         
        for (int j=1;j<=16;j++)
            for (int i=1;i<=n;i++) jump[i][j]=jump[jump[i][j-1]][j-1];
             
        build(rot[0],1,N);
        for (int i=1;i<=n;i++) if (!jump[i][0]) make(i,0);
         
        int ANS=0; char Q[3];
        while (task--) {
            scanf("%s",Q);
            if (Q[0]=='Q') {
                int x,y,k; scanf("%d%d%d",&x,&y,&k);
                x^=ANS; y^=ANS; k^=ANS;
                //printf("|%d %d %d
    ",x,y,k);
                int rr=lca(x,y); //printf("%d
    ",rr);
                //for (int i=1;i<=n;i++) printf("%d %d
    ",i,jump[i][0]);
                printf("%d
    ",ANS=ans[query(rot[x],rot[y],rot[rr],rot[jump[rr][0]],k)]);
                //for (int i=1;i<=n;i++) if (i==getfather(i)) printf("%d %d
    ",i,size[i]);
            } else {    
                int x,y; scanf("%d%d",&x,&y);
                x^=ANS; y^=ANS; connect(x,y); connect(y,x);
                //printf("|%d %d
    ",x,y);
                merge(x,y);
            }
        }
        return 0;
    }

     

  • 相关阅读:
    django-filter 使用Filter来筛选你的数据
    Django REST framework
    利用WSGI来部署你的网站
    [GitPython]使用python管理你的git库
    [模拟炉石](三)使用卡牌
    简单说pyglet.event
    [模拟炉石](二)下一步要解决的问题
    [模拟炉石](一)让游戏过程显示到cocos2d中
    docker系列之一:初见docker
    二分查找_递归实现_存在重复元素
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3678176.html
Copyright © 2011-2022 走看看