zoukankan      html  css  js  c++  java
  • Luogu_P3302 [SDOI2013]森林【题解】主席树 lca 启发式合并

    Luogu_P3302 [SDOI2013]森林

    主席树,启发式合并,lca


    luogu题面
    求树上路径的第k大,树之间还有合并。
    明显是主席树再加合并。

    先说链上第k大,其实就是(Tx+Ty-Tlca-Tlcafa)
    (T)表示权值线段树。
    主席树维护的是从根节点到当前节点的前缀和。
    ask的代码如下:

    inline int ask(int x,int y,int lcc,int lcf,int l,int r,int k){
        if(l==r) return b[l];
        int lz=sum(lc(x))+sum(lc(y))-sum(lc(lcc))-sum(lc(lcf));
        int mid=(l+r)>>1;
        if(k<=lz) return ask(lc(x),lc(y),lc(lcc),lc(lcf),l,mid,k);
        else return ask(rc(x),rc(y),rc(lcc),rc(lcf),mid+1,r,k-lz);
    }
    

    然后就是合并了。
    合并就是启发式合并。小的向大的合并。
    在dfs的过程中合并,更新线段树。
    dfs代码:

    void dfs(int x,int ft,int rrt){
        fa[x][0]=ft;
        for(int i=1;i<=tt;i++)
            fa[x][i]=fa[fa[x][i-1]][i-1];
        dep[x]=dep[ft]+1;vis[x]=1;f[x]=ft;siz[rrt]++;
        int k=lower_bound(b+1,b+1+cnt,a[x])-b;
        rt[x]=insert(rt[x],rt[ft],1,cnt,k);
        for(int i=head[x];i;i=nxt(i)){
            if(to(i)==ft) continue;
            dfs(to(i),x,rrt);
        }
    }
    

    那么整道题就几乎解决了,还有一些细节自己注意。
    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int maxn=1e5+10;
    int fe,n,m,q,tt,a[maxn],b[maxn],head[maxn],tot,fa[maxn][32],ans,cnt;
    int dep[maxn],rt[maxn],vis[maxn],f[maxn],zho,siz[maxn];
    struct node{
        int nxt,to;
        #define nxt(x) e[x].nxt
        #define to(x) e[x].to
    }e[maxn*4];
    struct tree{
        int lc,rc,sum;
        #define sum(x) t[x].sum
        #define lc(x) t[x].lc
        #define rc(x) t[x].rc
    }t[maxn*600];
    inline void add(int from,int to){to(++tot)=to;nxt(tot)=head[from];head[from]=tot;}
    inline int find(int x){return f[x]==x ? f[x] : f[x]=find(f[x]) ;}
    inline int insert(int p,int pr,int l,int r,int k){
        if(!p) p=++zho;
        sum(p)=sum(pr)+1;
        if(l==r) return p;
        int mid=(l+r)>>1;
        if(k<=mid) lc(p)=insert(lc(p),lc(pr),l,mid,k),rc(p)=rc(pr);
        else rc(p)=insert(rc(p),rc(pr),mid+1,r,k),lc(p)=lc(pr);
        return p;
    }
    inline int ask(int x,int y,int lcc,int lcf,int l,int r,int k){
        if(l==r) return b[l];
        int lz=sum(lc(x))+sum(lc(y))-sum(lc(lcc))-sum(lc(lcf));
        int mid=(l+r)>>1;
        if(k<=lz) return ask(lc(x),lc(y),lc(lcc),lc(lcf),l,mid,k);
        else return ask(rc(x),rc(y),rc(lcc),rc(lcf),mid+1,r,k-lz);
    }
    void dfs(int x,int ft,int rrt){
        fa[x][0]=ft;
        for(int i=1;i<=tt;i++)
            fa[x][i]=fa[fa[x][i-1]][i-1];
        dep[x]=dep[ft]+1;vis[x]=1;f[x]=ft;siz[rrt]++;
        int k=lower_bound(b+1,b+1+cnt,a[x])-b;
        rt[x]=insert(rt[x],rt[ft],1,cnt,k);
        for(int i=head[x];i;i=nxt(i)){
            if(to(i)==ft) continue;
            dfs(to(i),x,rrt);
        }
    }
    inline int lca(int x,int y){
        if(dep[y]>dep[x]) swap(x,y);
        for(int i=tt;i>=0;i--)
            if(dep[fa[x][i]]>=dep[y]) 
                x=fa[x][i];
        if(x==y) return x;
        for(int i=tt;i>=0;i--)
            if(fa[x][i]!=fa[y][i]) 
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    signed main(){
        scanf("%lld%lld%lld%lld",&fe,&n,&m,&q);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        cnt=unique(b+1,b+1+n)-b-1;
        for(int u,v,i=1;i<=m;i++) scanf("%lld%lld",&u,&v),add(u,v),add(v,u);
        tt=(int)log2(n)+1;
        for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0,i),f[i]=i;
        while(q--){
            char s[10];int x,y;scanf("%s%lld%lld",s,&x,&y);
            if(s[0]=='Q'){
                int z;scanf("%lld",&z);x^=ans,y^=ans,z^=ans;
                int lc=lca(x,y);ans=ask(rt[x],rt[y],rt[lc],rt[fa[lc][0]],1,cnt,z);
                printf("%lld
    ",ans);
            }
            else{
                x^=ans,y^=ans;add(x,y);add(y,x);
                int xx=find(x),yy=find(y);
                if(siz[xx]<siz[yy]) dfs(x,y,yy);
                else dfs(y,x,xx);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    打造自定义 eslint
    二叉树(三): 二叉查找树
    二叉树(二): 补充
    二叉树(一): 遍历
    redux 源码浅析
    react-redux 源码浅析
    WebComponents使用以及思考
    SHELL 语法以及实例
    React-Native 原生 APP 更新
    关于 cdn 在项目中的使用
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11600725.html
Copyright © 2011-2022 走看看