• P3302 [SDOI2013]森林 主席树 树上启发式合并


    题意:给定一片森林,n个点  每个点有权值  m 条边  q 个操作

    操作1: 求x y 路径上的第k大数

    操作2: x与y连边

    如果没有连边 那就是之前做的裸的树上主席树 

    连边的话只要用树上启发式合并即可  每次选小的树连到大的树上  (多一个log) 然后再从连接的点更新倍增数组   

    判断树的大小可以用并查集

    经历了无数次RE后发现是lca出了问题

    如果我们连边重构 update_LCA 时采用 lg[deep[u]] ,可能存在一种情况:这个点 i 原本的 ans[i][j],j 最大已经大于了 lg[deep[u]] (即原来深度更深),但是我们更新只是更新到 lg[deep[u]] 

    所以后来直接改成一个常数就没问题了

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RS(s) scanf("%s",s);
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define pb push_back
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    #define inf 0x3f3f3f3f
    #define ull unsigned long long
    const int N=8e5+5;
    int T[N],a[N],b[N],lson[N<<5],rson[N<<5],t[N<<5];
    int pos,head[N],lg[N],fa[N][20],dep[N],n,m,q,x,y,z,nn,ncnt;int f[N],siz[N];
    char s[2];
    struct Edge{int to,nex; }edge[N<<1];
    void add(int a,int b)
    {
        edge[++pos]=(Edge){b,head[a]};
        head[a]=pos;
    }
    void up(int x,int l,int r,int pre,int &pos)
    {
        pos=++ncnt;
        lson[pos]=lson[pre];rson[pos]=rson[pre];t[pos]=t[pre]+1;
        if(l==r)return ;int m=(l+r)>>1;
        if(x<=m)up(x,l,m,lson[pre],lson[pos]);
        else up(x,m+1,r,rson[pre],rson[pos]);
    }
    
    int qsum(int k,int l,int r,int lca,int falca,int pre,int pos)
    {
        if(l==r)return l;
        int x=t[lson[pos]]+t[lson[pre]]-t[lson[lca]]-t[lson[falca]];
    
        int m=(l+r)>>1;
        if(k<=x) return qsum(k,l,m,lson[lca],lson[falca],lson[pre],lson[pos]);
        else return qsum(k-x,m+1,r,rson[lca],rson[falca],rson[pre],rson[pos]);
    }
    
    void dfs(int x,int f)
    {
        dep[x]=dep[f]+1;
        fa[x][0]=f;
        up(a[x],1,nn,T[f],T[x]);
        for(int i=1;i<=16;i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;
            if(v==f)continue;
            dfs(v,x);
        }
    }
    
    int getlca(int x,int y)
    {
        if(dep[x]>dep[y])swap(x,y);
        repp(k,16,0)
        if(dep[fa[y][k]]>=dep[x])
        y=fa[y][k];
        if(x==y)return x;
    
        for(int k=16;k>=0;--k)
        if(fa[x][k]!=fa[y][k])
        x=fa[x][k],y=fa[y][k];
        return fa[x][0];
    }
    
    int find1(int x)
    {
        return x==f[x]?x:find1(f[x]);
    }
    void union1(int x,int y)
    {
        int a=find1(x),b=find1(y);
        if(siz[a]>=siz[b])
            siz[a]+=siz[b],f[b]=a;
        else
            siz[b]+=siz[a],f[a]=b;
    }
    
    int main()
    {
        int cas;cin>>cas;
    
        scanf("%d%d%d",&n,&m,&q);
        rep(i,1,n)f[i]=i,siz[i]=1;
    
        rep(i,1,n)scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        nn=unique(b+1,b+1+n)-b-1;
    
        rep(i,1,n)a[i]=lower_bound(b+1,b+1+nn,a[i])-b;
    
        rep(i,1,m)
        {
            int u,v;scanf("%d%d",&u,&v);add(u,v);add(v,u);union1(u,v);
        }
        
        rep(i,1,n)
        if(f[i]==i)dfs(i,0);
        
        int ans=0;
        while(q--)
        {
            RS(s);
            if(s[0]=='Q')
            {
                int k;
                scanf("%d%d%d",&x,&y,&k);x^=ans;y^=ans;k^=ans;
                int lca=getlca(x,y);
                printf("%d
    ",ans=b[qsum(k,1,nn,T[lca],T[fa[lca][0]],T[x],T[y] )] );
            }
            else
            {
                int x,y;scanf("%d%d",&x,&y);x^=ans;y^=ans;
                add(x,y);add(y,x);
                int a=find1(x),b=find1(y);
                if(siz[a]>siz[b])swap(a,b),swap(x,y);
                f[a]=b;siz[b]+=siz[a];
                dfs(x,y);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    树套树
    Luogu P2839 [国家集训队]middle
    苟随笔
    BJOI2014 大融合
    轻量树上问题选做
    sb的斜率优化笔记
    CDialogEx::OnPaint()的问题,或者为什么在对话框程序的OnPaint中绘图无效的问题
    VC6的工程转到VC2010或更高版本出现fatal error C1189编译错误的解决方法
    C语言实现的反转字符串
    在终端输入npm run serve时出现npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! test_vue_0613@1.0.0 dev: 错误的解决方法
  • 原文地址:https://www.cnblogs.com/bxd123/p/11288387.html
Copyright © 2020-2023  润新知