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));
        
    }
    
  • 相关阅读:
    sfs2x 连接 mongodb
    java websocket
    webstorm 4.0 注册码
    解决 sfs2 admin tool 找不到扩展
    window 注册表五大类
    opengl 学习第二日
    java google Protobuf
    扩展 java sencha touch PhonegapPlugin
    sencha touch2 kryonet socket phonegap 通信 作者:围城
    sencha touch2 layout 笔记
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/12209965.html
Copyright © 2011-2022 走看看