zoukankan      html  css  js  c++  java
  • 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并

    我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时间复杂度为O(n*log),因为每个的节点只会作为小的部分合并,因此他所在的一小部分至少变大2倍,对于每一个节点他作为被合并方最多log次,因此其复杂度为O(n*log),而这个是绝对跑不满还差很多的,我们视他为无常数就好了,当然这一切都是建立在无拆分操作的基础之上,只要有了拆分启发式合并的复杂度就是暴力了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define MAXN 80001
    using namespace std;
    inline int read(){
        register int sum=0;register char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')sum=(sum<<1)+(sum<<3)+ch-'0',ch=getchar();
        return sum;
    }
    int n,m,T,fa[MAXN],size[MAXN],f[MAXN][20];
    struct Via{
        int to,next;
    }c[MAXN<<1];
    int head[MAXN],t;
    struct Seg_Tree{
        Seg_Tree *ch[2];
        int size;
    }*root[MAXN],*null;
    int pos[MAXN],a[MAXN],deep[MAXN];
    int Hash[MAXN],len;
    bool v[MAXN];
    //*********************Define********************//
    inline int find(int x){
        return x==fa[x]?x:(fa[x]=find(fa[x]));
    }
    inline void Unit_to_(int x,int y){
        fa[find(x)]=find(y);
    }
    //*******************Union_Find_Sets*************//
    inline void add(int x,int y){
        c[++t].to=y,c[t].next=head[x],head[x]=t;
    }
    //********************Maintain_Tree**************//
    int comp(const int x,const int y){
        return a[x]<a[y];
    }
    inline void HASH(){
        sort(pos+1,pos+n+1,comp);
        for(register int i=1;i<=n;i++)
            if(i==1||a[pos[i]]!=a[pos[i-1]])Hash[++len]=a[pos[i]],a[pos[i]]=len;
            else a[pos[i]]=len;
    }
    //********************Hash**********************//
    void ins(Seg_Tree *&p,Seg_Tree *last,int l,int r,int key){
        p=new Seg_Tree,*p=*last,++p->size;if(l==r)return;
        if(key<=((l+r)>>1))ins(p->ch[0],last->ch[0],l,((l+r)>>1),key);
        else ins(p->ch[1],last->ch[1],((l+r)>>1)+1,r,key);
    }
    void Dfs_Build(int x,int Fa){
        deep[x]=deep[Fa]+1;v[x]=1;
        for(register int i=1;i<20;i++)f[x][i]=f[f[x][i-1]][i-1];
        ins(root[x],root[Fa],1,len,a[x]);
        for(register int i=head[x];i;i=c[i].next)
            if(c[i].to!=Fa) f[c[i].to][0]=x,Dfs_Build(c[i].to,x);
    }
    int query(Seg_Tree *A1,Seg_Tree *A2,Seg_Tree *B1,Seg_Tree *B2,int l,int r,int k){
        if(l==r)return l;register int sum=A1->ch[0]->size-A2->ch[0]->size+B1->ch[0]->size-B2->ch[0]->size;
        if(sum>=k)return query(A1->ch[0],A2->ch[0],B1->ch[0],B2->ch[0],l,((l+r)>>1),k);
        else return query(A1->ch[1],A2->ch[1],B1->ch[1],B2->ch[1],((l+r)>>1)+1,r,k-sum);
    }
    void Del(Seg_Tree *p,Seg_Tree *last){
        if(p==last)return;
        Del(p->ch[0],last->ch[0]),Del(p->ch[1],last->ch[1]);
        delete p;
    }
    void Delete(int x,int fa){
        for(register int i=head[x];i;i=c[i].next)
            if(c[i].to!=fa)Delete(c[i].to,x);
        Del(root[x],root[fa]),root[x]=null;
    }
    //********************Seg_Tree******************//
    inline int Lca(int x,int y){
        if(deep[x]<deep[y])x^=y^=x^=y;
        register int k=deep[x]-deep[y];
        for(register int i=0;(1<<i)<=k;i++)
            if(k&(1<<i)) x=f[x][i];
        if(x==y)return x;
        for(register int i=19;i>=0;i--)
            if(f[x][i]!=f[y][i])
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    //*********************LCA*********************//
    inline void Init(){
        scanf("%*d"),n=read(),m=read(),T=read();
        null=new Seg_Tree,null->ch[0]=null->ch[1]=null,null->size=0,root[0]=null;
        for(register int i=1;i<=n;i++)a[i]=read(),pos[i]=i,root[i]=null,size[i]=1,fa[i]=i;HASH();
        for(register int i=1,x,y;i<=m;i++)x=read(),y=read(),add(x,y),add(y,x),size[find(y)]+=size[find(x)],Unit_to_(x,y);
        for(register int i=1;i<=n;i++)if(!v[i])Dfs_Build(find(i),0);
    }
    inline void Work(){
        register int x,y,k,lca,ans=0;register char s[1];
        while(T--){
            scanf("%s",s);
            if(s[0]=='Q'){
                x=read()^ans,y=read()^ans,k=read()^ans,lca=Lca(x,y);
                printf("%d
    ",(ans=Hash[query(root[x],root[lca],root[y],root[f[lca][0]],1,len,k)]));
            }else{
                x=read()^ans,y=read()^ans;if(size[find(x)]>size[find(y)])x^=y^=x^=y;
                Delete(find(x),0),size[find(y)]+=size[find(x)],Unit_to_(x,y);
                f[x][0]=y,add(x,y),add(y,x),Dfs_Build(x,y);
            }
        }
    }
    //*********************Main********************//
    int main(){
        Init();
        Work();
        return 0;
    }
  • 相关阅读:
    Hello world
    Kubernetes容器云平台建设实践
    工作方法决定自己的发展
    Excel中对身份证号的处理
    详解慢查询日志的相关设置及mysqldumpslow工具
    安全测试工具简介
    Redis使用
    linux centos 查看防火墙firewalld、iptables状态
    悄悄地存在这里,因为里面的一句话
    GAE Python 2009322
  • 原文地址:https://www.cnblogs.com/TSHugh/p/7288852.html
Copyright © 2011-2022 走看看