zoukankan      html  css  js  c++  java
  • 【BZOJ】3123: [Sdoi2013]森林

    【算法】可持久化线段树(主席树)+启发式合并+LCA

    【题意】给定森林,每次询问u,v路径上的第k小,或给u,v连边(保证森林),n<=8*10^4。

    【题解】

    区间第k小:离散化,在上一个位置的基础上建可持久化权值线段树,每次比较左子树和k并找到第一个大于等于k的位置。

    树上第k小:每个点上其父亲的基础上建树,ans=ask(u)+ask(v)-ask(lca(u,v))-ask(fa[lca(u,v)]),恰好是不重不漏的一条链。

    连边:因为保证森林,只要使用启发式合并的方法,对点数少的树DFS重建树即可,启发式合并保证每个点至多重建log n次。

    复杂度O(n log2n)。

    注意:数据中第一行testcase为数据编号,不是组数。

    注意:空间开大!空间复杂度O(n log2n)。

    注意:代入主席树用root!

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    using namespace std;
    const int maxn=100010;
    struct tree{int l,r,sum;}t[40000010];
    struct edge{int v,from;}e[800010];
    int a[maxn],root[maxn],Root[maxn],f[maxn][30],tot,cnt,first[maxn],sz,size[maxn],deep[maxn],p[10],n,m,T,b[maxn];
    bool vis[maxn];
    
    int read()
    {
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    void insert(int u,int v)
    {cnt++;e[cnt].v=v;e[cnt].from=first[u];first[u]=cnt;}
    void build(int l,int r,int &x,int y,int c){
        x=++sz;
        t[x]=t[y];t[x].sum++;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(c<=mid)build(l,mid,t[x].l,t[y].l,c);
        else build(mid+1,r,t[x].r,t[y].r,c);
    }
    
    void dfs(int x,int fa,int rt){
        Root[x]=rt;size[x]=1;vis[x]=1;
        build(1,tot,root[x],root[fa],a[x]);
        for(int j=1;(1<<j)<=deep[x];j++)f[x][j]=f[f[x][j-1]][j-1];
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
            f[e[i].v][0]=x;
            deep[e[i].v]=deep[x]+1;
            dfs(e[i].v,x,rt);
            size[x]+=size[e[i].v];
        }
    }
    int lca(int x,int y){
        if(deep[x]<deep[y])swap(x,y);
        int d=deep[x]-deep[y];
        for(int j=0;(1<<j)<=d;j++)if((1<<j)&d)x=f[x][j];//&...
        if(x==y)return x;
        for(int j=20;j>=0;j--)if((1<<j)<=deep[x]&&f[x][j]!=f[y][j]){
            x=f[x][j];y=f[y][j];
        }
        return f[x][0];
    }
    int ask(int l,int r,int c){
        if(l==r)return l;
        int sum=t[t[p[1]].l].sum+t[t[p[2]].l].sum-t[t[p[3]].l].sum-t[t[p[4]].l].sum;
        int mid=(l+r)>>1;
        if(sum>=c){
            for(int i=1;i<=4;i++)p[i]=t[p[i]].l;
            return ask(l,mid,c);
        }
        else{
            for(int i=1;i<=4;i++)p[i]=t[p[i]].r;
            return ask(mid+1,r,c-sum);
        }
    }  
    int main(){
        int Test=read();//Test=1
        n=read();m=read();T=read();
        for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i];
        sort(b+1,b+n+1);tot=n;
        tot=unique(b+1,b+tot+1)-b-1;
        for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
        for(int i=1;i<=m;i++){
            int u=read(),v=read();
            insert(u,v);insert(v,u);
        }
        for(int i=1;i<=n;i++)if(!vis[i])dfs(i,0,i);
        char s[10];
        int lastans=0;
        for(int i=1;i<=T;i++){
            scanf("%s",s);
            if(s[0]=='Q'){
                int u=read()^lastans,v=read()^lastans,w=read()^lastans;
                p[1]=root[u];p[2]=root[v];p[3]=root[lca(u,v)];p[4]=root[f[lca(u,v)][0]];//用root!
                lastans=b[ask(1,tot,w)];
                printf("%d
    ",lastans);
            }
            else{
                int u=read()^lastans,v=read()^lastans;
                if(size[Root[u]]<size[Root[v]])swap(u,v);
                size[Root[u]]+=size[Root[v]];insert(u,v);insert(v,u);
                f[v][0]=u;
                deep[v]=deep[u]+1;
                dfs(v,u,Root[u]);
                
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    操作系统与进程.md
    解决粘包现象
    Python3网络爬虫开发实战
    Django学习目录
    前端学习目录
    MySQL数据库学习目录
    第一章 开发环境配置
    15.3 Scrapyd 对接 Docker
    13.4 Spider 的用法
    9.1 代理的设置
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7471643.html
Copyright © 2011-2022 走看看