zoukankan      html  css  js  c++  java
  • BZOJ3123: [Sdoi2013]森林

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3123

    主席树+启发式合并。

    首先对于每棵树建主席树,然后合并的时候就把点数小的暴力插进点数大的那棵树里面。

    然后查询的话就在主席树上二分就可以了。

    注意点:在暴力重建的过程中边是确确实实要连的否则会丢失信息。。

    调了很久TAT。。

    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define rep(i,l,r) for (int i=l;i<=r;i++)
    #define down(i,l,r) for (int i=l;i>=r;i--)
    #define clr(x,y) memset(x,y,sizeof(x))
    #define inf 1000000009
    #define ll long long
    using namespace std;
    struct data{int obj,pre;
    }e[165000];
    int sum[24005000],root[80050],ls[24005000],rs[24005000];
    int head[80050],dep[80050],fa[80050][21],a[80050],b[80050],s[80050];
    int bin[21];
    int n,m,q,ans,tot,cnt,tt,num;
    char ch[2];
    int read(){
        int x=0,f=1; char ch=getchar();
        while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();}
        while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    void insert(int x,int y){
        e[++tot].obj=y; e[tot].pre=head[x]; head[x]=tot;
    }
    void add(int l,int r,int x,int &y,int val){
        y=++cnt;
        sum[y]=sum[x]+1;
        if (l==r) return;
        int mid=(l+r)/2;
        if (val<=mid) rs[y]=rs[x],add(l,mid,ls[x],ls[y],val);
        if (val>mid) ls[y]=ls[x],add(mid+1,r,rs[x],rs[y],val);
    }
    void dfs(int u){
        s[u]=1;
        add(1,num,root[fa[u][0]],root[u],a[u]);
        rep(i,1,20) if (dep[u]>=bin[i]) fa[u][i]=fa[fa[u][i-1]][i-1];    
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;
            if (v!=fa[u][0]){
                fa[v][0]=u; dep[v]=dep[u]+1;
                dfs(v);
                s[u]+=s[v];
            }
        }
    }
    int lca(int x,int y){
        if (dep[x]<dep[y]) swap(x,y);
        int t=dep[x]-dep[y];
        rep(i,0,20) if (t&bin[i]) x=fa[x][i];
        down(i,20,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
        if (x==y) return x;
        return fa[x][0]; 
    }
    void cl(int u,int f){
        clr(fa[u],0); dep[u]=0;
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;
            if (v!=f) cl(v,u);
        }
    }
    void link(int x,int y){
        cl(y,0);
        dep[y]=dep[x]+1; fa[y][0]=x; insert(x,y); insert(y,x);
        dfs(y);
    }
    void rebuild(int x,int y){
        int sx=x,sy=y;
        int t=dep[x]; rep(i,0,20) if (t&bin[i]) x=fa[x][i];
        t=dep[y]; rep(i,0,20) if (t&bin[i]) y=fa[y][i];
        if (s[x]<s[y]) swap(x,y),swap(sx,sy);
        s[x]+=s[y]; link(sx,sy);    
    }
    int solve(int x,int y,int k){
        int z=lca(x,y),t=fa[z][0],a=root[x],b=root[y],c=root[z],d=root[t];
        int l=1,r=num,now=0;
        while (l<r){
            int mid=(l+r)/2;
            now=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
            if (now<k) {
                k-=now; 
                a=rs[a],b=rs[b],c=rs[c],d=rs[d];
                l=mid+1;
            }
            else {
                a=ls[a],b=ls[b],c=ls[c],d=ls[d];
                r=mid;
            }
        }
        return l;
    }
    int Find(int x){
        int l=1,r=num,mid;
        while (l<r){
            mid=(l+r)/2;
            if (b[mid]==x) return mid;
            if (b[mid]<x) l=mid+1;
            else r=mid-1;
        }
        return l;
    }
    int main(){
        tt=read();
        bin[0]=1; rep(i,1,20) bin[i]=bin[i-1]*2; 
        ans=0;
            n=read(); m=read(); q=read(); 
            rep(i,1,n) a[i]=read(),b[i]=a[i];
            sort(b+1,b+1+n); num=unique(b+1,b+1+n)-b-1;
            rep(i,1,n) a[i]=Find(a[i]);
            rep(j,1,m){
                int x=read(),y=read();
                insert(x,y); insert(y,x);
            }
            rep(i,1,n) if (!root[i]) dfs(i);
            rep(i,1,q){
                scanf("%s",ch);
                if (ch[0]=='Q'){
                    int x=read()^ans,y=read()^ans,k=read()^ans;
                    ans=b[solve(x,y,k)];
                    printf("%d
    ",ans);
                }
                else {
                    int x=read()^ans,y=read()^ans;
                    rebuild(x,y);
                }
            }
        return 0;
    }
  • 相关阅读:
    Centos常用快捷键
    ngnix笔记
    转载申明
    Linux 最小安装常用包
    update-alternatives关键解疑
    使用Java语言开发机器学习框架和参数服务器
    storm实践
    JVM线程状态,park, wait, sleep, interrupt, yeild 对比
    PHP版本解密openrtb中的价格
    Minimum Path Sum
  • 原文地址:https://www.cnblogs.com/ctlchild/p/5149169.html
Copyright © 2011-2022 走看看