zoukankan      html  css  js  c++  java
  • 【题解】Query on a tree III [SP1487] [Bzoj1803]

    【题解】Query on a tree III [SP1487] [Bzoj1803]

    传送门:( ext{Query on a tree III [SP1487]}) ( ext{[Bzoj1803]})

    【题目描述】

    给出一棵 (n) ((n leqslant 10^5)) 个节点的树,每个点都带有点权,一共 (m) ((m leqslant 10^4)) 个询问,每次查询以 (x) 为根的子树内权值第 (k) 小的节点编号。

    【分析】

    发现网上所有题解都是主席树,我线段树合并表示不服!

    明明就是树上线段树合并的板子,居然没一个人写。。。

    查询若干个子树的相关信息且不强制在线,可以先用链表把询问挂到 (x) 上,初始化对每个节点开一棵,从下往上逐步合并,每合并完一棵子树就把链表掏出来查询一波信息,然后再继续往上合并。

    由于节点权值两两不同,所以离散化后映射一下每个权值所在的节点编号即可。

    时间复杂度:(O((n+m)logn))

    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define LL long long
    #define Re register int
    using namespace std;
    const int N=1e5+3;
    int n,m,o,x,y,T,b[N],A[N],ID[N],Ans[N],head[N];
    struct QAQ{int to,next;}a[N<<1];
    inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
    inline void in(Re &x){
        Re fu=0;x=0;char ch=getchar();
        while(ch<'0'||ch>'9')fu|=ch=='-',ch=getchar();
        while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=fu?-x:x;
    }
    struct QWQ{//用链表挂询问
        int o,head[N];
        struct QAQ{int k,id,next;}a[N<<1];
        inline void add(Re x,Re k,Re id){a[++o].k=k,a[o].id=id,a[o].next=head[x],head[x]=o;}
    }T0;
    struct Segment_Tree{
        #define pl tr[p].lp
        #define pr tr[p].rp
        #define mid (L+R>>1)
        int O,pt[N];
        struct QAQ{int S,lp,rp;}tr[N*18];
        inline void change(Re &p,Re L,Re R,Re x){//单点修改
            if(!p)p=++O;++tr[p].S;
            if(L==R)return;
            if(x<=mid)change(pl,L,mid,x);
            else change(pr,mid+1,R,x);
        }
        inline void build(){for(Re i=1;i<=n;++i)change(pt[i],1,m,A[i]);}//初始化建立n棵权值线段树
        inline int merge(Re p,Re q){//线段树合并
            if(!p)return q;if(!q)return p;
            tr[p].S+=tr[q].S;
            pl=merge(pl,tr[q].lp);
            pr=merge(pr,tr[q].rp);
            return p;
        }
        inline int ask(Re p,Re L,Re R,Re k){//查询第k小
            if(L==R)return ID[L];
            Re tmp=tr[pl].S;
            if(tmp>=k)return ask(pl,L,mid,k);
            else return ask(pr,mid+1,R,k-tmp);
        }
    }T1;
    inline void dfs(Re x,Re fa){
        for(Re i=head[x],to;i;i=a[i].next)
            if((to=a[i].to)!=fa)dfs(to,x),T1.pt[x]=T1.merge(T1.pt[x],T1.pt[to]);//合并儿子
        for(Re i=T0.head[x];i;i=T0.a[i].next)Ans[T0.a[i].id]=T1.ask(T1.pt[x],1,m,T0.a[i].k);//把x节点上挂着的询问都拿出来跑一下
    }
    int main(){
    //  freopen("123.txt","r",stdin);
        in(n),m=n-1;
        for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
        while(m--)in(x),in(y),add(x,y),add(y,x);
        sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1;//离散化
        for(Re i=1;i<=n;++i)A[i]=lower_bound(b+1,b+m+1,A[i])-b,ID[A[i]]=i;
        T1.build(),in(T);
        for(Re i=1;i<=T;++i)in(x),in(y),T0.add(x,y,i);//把询问挂到链表上
        dfs(1,0);
        for(Re i=1;i<=T;++i)printf("%d
    ",Ans[i]);
    }
    

    另附主席树代码:

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define LL long long
    #define Re register int
    using namespace std;
    const int N=1e5+3;
    int n,m,o,x,y,T,dfn_o,b[N],A[N],AA[N],ID[N],dfn[N],size[N],head[N];
    struct QAQ{int to,next;}a[N<<1];
    inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
    inline void in(Re &x){
        Re fu=0;x=0;char ch=getchar();
        while(ch<'0'||ch>'9')fu|=ch=='-',ch=getchar();
        while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=fu?-x:x;
    }
    struct Segment_Tree{
        #define pl tr[p].lp
        #define pr tr[p].rp
        #define mid (L+R>>1)
        int O,pt[N];
        struct QAQ{int S,lp,rp;}tr[N*18];
        inline void creat(Re &p,Re q,Re L,Re R,Re x){
            tr[p=++O]=tr[q],++tr[p].S;
            if(L==R)return;
            if(x<=mid)creat(pl,tr[q].lp,L,mid,x);
            else creat(pr,tr[q].rp,mid+1,R,x);
        }
        inline int ask(Re p,Re q,Re L,Re R,Re k){//查询区间第k小
            if(L==R)return ID[L];
            Re tmp=tr[tr[q].lp].S-tr[pl].S;
            if(tmp>=k)return ask(pl,tr[q].lp,L,mid,k);
            else return ask(pr,tr[q].rp,mid+1,R,k-tmp);
        }
    }T1;
    inline void dfs(Re x,Re fa){
        AA[dfn[x]=++dfn_o]=A[x],size[x]=1;
        for(Re i=head[x],to;i;i=a[i].next)
            if((to=a[i].to)!=fa)dfs(to,x),size[x]+=size[to];
    }
    int main(){
    //  freopen("123.txt","r",stdin);
        in(n),m=n-1;
        for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
        while(m--)in(x),in(y),add(x,y),add(y,x);
        sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1;//离散化
        for(Re i=1;i<=n;++i)A[i]=lower_bound(b+1,b+m+1,A[i])-b,ID[A[i]]=i;
        dfs(1,0);
        for(Re i=1;i<=n;++i)T1.creat(T1.pt[i],T1.pt[i-1],1,m,AA[i]);//建主席树
        in(T);
        while(T--)in(x),in(y),printf("%d
    ",T1.ask(T1.pt[dfn[x]-1],T1.pt[dfn[x]+size[x]-1],1,m,y));
        
    }
    
  • 相关阅读:
    Android Studio库依赖问题
    Android学习笔记View的工作原理
    专用服务器模式&共享服务器模式
    Linux命令学习总结:shutdown
    Linux查看设置系统时区
    ORA-01950: no privileges on tablespace xxxx
    complex(x):创建一个复数
    python常用函数之--求绝对值函数:abs(x)
    python学习链接:
    requirejs学习博客址分享
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/12209965.html
Copyright © 2011-2022 走看看