zoukankan      html  css  js  c++  java
  • BZOJ 3123 SDOI2013 森林

    首先对于查询操作就是裸的COT QAQ

    在树上DFS建出主席树就可以了

    对于连接操作,我们发现并没有删除

    所以我们可以进行启发式合并,每次将小的树拍扁插入大的树里并重构即可

    写完了之后第一个和第二个点迷のRE

    然后又重新写了一遍就A了(并不知道为什么,难道第一遍写挫了?

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
     
    const int maxn=100010;
    int T,n,m,Q,u,v,k,lca,w;
    int ans=0;
    char ch;
    int p[maxn];
    int fa[maxn],dep[maxn],sz[maxn];
    int anc[maxn][20];
    int h[maxn],cnt=0;
    struct edge{
        int to,next;
    }G[maxn<<1];
    void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;}
    int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);}
     
    int a[maxn];
    struct val{
        int v,id;
    }c[maxn];
    bool cmpv(const val &A,const val &B){return A.v<B.v;}
    bool cmpid(const val &A,const val &B){return A.id<B.id;}
     
    int tot=0,rt[maxn];
    struct Seg_Tree{
        int L,R,v;
    }t[11000010];
     
    void read(int &num){
        num=0;ch=getchar();
        while(ch<'!')ch=getchar();
        while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    }
    void build(int &o,int L,int R){
        o=++tot;
        if(L==R)return;
        int mid=(L+R)>>1;
        build(t[o].L,L,mid);
        build(t[o].R,mid+1,R);
    }
    void modify(int &o,int now,int L,int R,int p){
        t[++tot]=t[now];o=tot;
        if(L==R){t[o].v++;return;}
        int mid=(L+R)>>1;
        if(p<=mid)modify(t[o].L,t[now].L,L,mid,p);
        else modify(t[o].R,t[now].R,mid+1,R,p);
        t[o].v=t[t[o].L].v+t[t[o].R].v;
    }
    void DFS(int u,int f){
        anc[u][0]=f;
        modify(rt[u],rt[f],1,m,c[u].v);
        for(int i=1;i<=18;++i){
            if(anc[u][i-1]!=0){
                int a=anc[u][i-1];
                anc[u][i]=anc[a][i-1];
            }else anc[u][i]=0;
        }
        for(int i=h[u];i;i=G[i].next){
            int v=G[i].to;
            if(v==f)continue;
            dep[v]=dep[u]+1;
            DFS(v,u);
        }return;
    }
    int LCA(int p,int q){
        if(dep[p]<dep[q])swap(p,q);
        int d=dep[p]-dep[q];
        for(int i=18;i>=0;--i){
            if(d>>i&1)p=anc[p][i];
        }
        if(p==q)return p;
        for(int i=18;i>=0;--i){
            if(anc[p][i]!=anc[q][i]&&anc[p][i]!=0)p=anc[p][i],q=anc[q][i];
        }return anc[p][0];
    }
    int ask(int u,int v,int lca,int L,int R,int k){
        if(L==R)return L;
        int mid=(L+R)>>1;
        int now=t[t[u].L].v+t[t[v].L].v-2*t[t[lca].L].v+(w<=mid&&w>=L);
        if(k>now)return ask(t[u].R,t[v].R,t[lca].R,mid+1,R,k-now);
        else return ask(t[u].L,t[v].L,t[lca].L,L,mid,k);
    }
    int main(){
        read(T);read(n);read(m);read(Q);
        for(int i=1;i<=n;++i)read(c[i].v),c[i].id=i,a[i]=c[i].v;
        for(int i=1;i<=n;++i)fa[i]=i;
        for(int i=1;i<=m;++i){
            read(u);read(v);
            add(u,v);add(v,u);
            int d1=ufs(u),d2=ufs(v);
            if(d1!=d2)fa[d1]=d2;
        }m=0;
        sort(c+1,c+n+1,cmpv);sort(a+1,a+n+1);
        for(int i=1;i<=n;++i){
            if(i==1||a[i]!=a[i-1])c[i].v=++m,p[m]=a[i];
            else c[i].v=m;
        }
        sort(c+1,c+n+1,cmpid);
        build(rt[0],1,m);
        for(int i=1;i<=n;++i){
            if(ufs(i)==i)DFS(i,0);
            sz[ufs(i)]++;
        }
        while(Q--){
            ch=getchar();
            while(ch<'!')ch=getchar();
            if(ch=='Q'){
                scanf("%d%d%d",&u,&v,&k);
                u^=ans;v^=ans;k^=ans;
                lca=LCA(u,v);w=c[lca].v;
                //cout<<u<<' '<<v<<' '<<k<<endl;
                ans=p[ask(rt[u],rt[v],rt[lca],1,m,k)];
                printf("%d
    ",ans);
            }else{
                scanf("%d%d",&u,&v);
                u^=ans;v^=ans;
                //cout<<u<<' '<<v<<endl;
                int d1=ufs(u),d2=ufs(v);
                //cout<<d1<<' '<<d2<<endl;
                if(sz[d1]<sz[d2])swap(u,v),swap(d1,d2);
                sz[d1]+=sz[d2];
                if(d1!=d2)fa[d2]=d1;//d2->d1
                dep[v]=dep[u]+1;
                DFS(v,u);add(u,v);add(v,u);
            }
        }return 0;
    }
    

      

  • 相关阅读:
    vue使用elementui合并table
    使用layui框架导出table表为excel
    vue使用elementui框架,导出table表格为excel格式
    前台传数据给后台的几种方式
    uni.app图片同比例缩放
    我的博客
    【C语言】取16进制的每一位
    SharePoint Solution 是如何部署的呢 ???
    无效的数据被用来用作更新列表项 Invalid data has been used to update the list item. The field you are trying to update may be read only.
    SharePoint 判断用户在文件夹上是否有权限的方法
  • 原文地址:https://www.cnblogs.com/joyouth/p/5392813.html
Copyright © 2011-2022 走看看