zoukankan      html  css  js  c++  java
  • P3302 [SDOI2013]森林(主席树+启发式合并)

    P3302 [SDOI2013]森林

    主席树+启发式合并

    (我以前的主席树板子是错的.......坑了我老久TAT)

    第k小问题显然是主席树。

    我们对每个点维护一棵包含其子树所有节点的主席树

    询问(x,y)的时候用倍增找到(x,y)的lca,蓝后树上差分一下,即:

    $total_{size}=sum[x]+sum[y]-sum[lca]-sum[fa[lca]]$

    至于合并两棵树........我们把小的那棵树接到大的那棵上,并把小树上的主席树都重构一遍

    这就是启发式合并,合并的复杂度大概为$O(nlogn)$

    数据......离散化一下就好辣

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline void Swap(int &a,int &b){a^=b^=a^=b;}
    void read(int &x){
        static char c=getchar();x=0; int f=1;
        while(c<'0'||c>'9') f=f&&(c!='-'),c=getchar();
        while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
        x=f?x:-x;
    }
    #define N 80005
    #define W 20000005
    int TAT,n,m,T,tn,a[N],b[N],w[N],Rt[N],Siz[N],Pre;
    int u,rt[N],lc[W],rc[W],siz[W];
    int fa[N],Fa[18][N],d[N];
    int cnt,hd[N],nxt[N<<1],ed[N],poi[N<<1];
    bool vis[N];
    inline void adde(int x,int y){
        nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt,
        ed[x]=cnt, poi[cnt]=y;
    }
    inline int Id(int x){return lower_bound(b+1,b+tn+1,x)-b;}
    #define mid (l+r)/2
    void Ins(int &o,int p,int l,int r,int x){
        if(!o) o=++u;
        siz[o]=siz[p]+1;
        if(l==r) return ;
        if(x<=mid) rc[o]=rc[p],Ins(lc[o],lc[p],l,mid,x);
        else lc[o]=lc[p],Ins(rc[o],rc[p],mid+1,r,x);
    }
    int Ask(int x,int y,int c1,int c2,int l,int r,int k){
        if(l==r) return b[l];
        int tmp=siz[lc[x]]+siz[lc[y]]-siz[lc[c1]]-siz[lc[c2]];
        if(k<=tmp) return Ask(lc[x],lc[y],lc[c1],lc[c2],l,mid,k);
        else return Ask(rc[x],rc[y],rc[c1],rc[c2],mid+1,r,k-tmp);
    }
    void dfs(int x,int RT){
        Fa[0][x]=fa[x]; d[x]=d[fa[x]]+1; vis[x]=1;
        for(int i=1;i<=17;++i) Fa[i][x]=Fa[i-1][Fa[i-1][x]];//不能写成(1<<i)<=d[x],因为我们并没有把之前的废弃点完全删除,必须全部覆盖掉
        ++Siz[RT]; Rt[x]=RT;
        Ins(rt[x],rt[fa[x]],1,tn,Id(a[x]));
        for(int i=hd[x];i;i=nxt[i])
            if(poi[i]!=fa[x])
                fa[poi[i]]=x,dfs(poi[i],RT);
    }
    int LCA(int x,int y){
        if(d[x]<d[y]) Swap(x,y);
        for(int i=17;i>=0;--i) if(d[Fa[i][x]]>=d[y]) x=Fa[i][x];
        if(x==y) return x;
        for(int i=17;i>=0;--i) if(Fa[i][x]!=Fa[i][y]) x=Fa[i][x],y=Fa[i][y];
        return Fa[0][x];
    }
    int main(){
        register int i; char opt[3]; int q1,q2,q3,lca;
        read(TAT);read(n);read(m);read(T);
        for(i=1;i<=n;++i) read(a[i]),w[i]=a[i];
        while(m--) read(q1),read(q2),adde(q1,q2),adde(q2,q1);
        sort(w+1,w+n+1); b[tn=1]=w[1];
        for(i=2;i<=n;++i) if(w[i]!=w[i-1]) b[++tn]=w[i]; //离散化
        for(i=1;i<=n;++i) if(!vis[i]) dfs(i,i);
        while(T--){
            scanf("%s",opt);read(q1);read(q2);q1^=Pre;q2^=Pre;
            if(opt[0]=='L'){
                adde(q1,q2),adde(q2,q1);
                if(Siz[Rt[q1]]<Siz[Rt[q2]]) Swap(q1,q2);
                fa[q2]=q1; dfs(q2,Rt[q1]);//启发式合并,小树连到大树上
            }else{
                read(q3); q3^=Pre; lca=LCA(q1,q2);
                Pre=Ask(rt[q1],rt[q2],rt[lca],rt[fa[lca]],1,tn,q3);
                printf("%d
    ",Pre);
            }
        }return 0;
    }
  • 相关阅读:
    判断是否是移动端
    html上传文件类型限制accept的全部属性值
    前端cropper裁剪图像大小(原创)
    eslint加不加分号
    手机浏览器使用rem 自适应html宽度大小
    DOMContentLoaded与load的区别
    ES6语法find查找匹配数组
    React的JSX语法
    React的基本使用
    React简介
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10604911.html
Copyright © 2011-2022 走看看