zoukankan      html  css  js  c++  java
  • Count on a tree

    bzoj  2588: Spoj 10628. Count on a tree

    http://www.lydsy.com/JudgeOnline/problem.php?id=2588

    Description

    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

    Input

    第一行两个整数N,M。
    第二行有N个整数,其中第i个整数表示点i的权值。
    后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
    最后M行每行两个整数(u,v,k),表示一组询问。

    Output

    M行,表示每个询问的答案。最后一个询问不输出换行符

    Sample Input

    8 5
    105 2 9 3 8 5 7 7
    1 2
    1 3
    1 4
    3 5
    3 6
    3 7
    4 8
    2 5 1
    0 5 2
    10 5 3
    11 5 4
    110 8 2

    Sample Output

    2
    8
    9
    105
    7

    HINT

    HINT:

    N,M<=100000

    暴力自重。。。

    Source

    鸣谢seter

    数据结构:主席树

    辅助算法:LCA

    以点的dfs序为下标,以点权为区间建立主席树

    以前做过的主席树在序列上,所以是以前一个节点的线段树为基准建立的

    这里在树上,所以可以考虑以根为基准建立线段树

    u,v间增加的点数=cnt[u]+cnt[v]-cnt[LCA(u,v)]-cnt[father[LCA(u,v)]]

    #include<cstdio>
    #include<algorithm>
    #define N 100001
    using namespace std;
    struct count
    {
        private:
            struct node{int l,r,cnt;}tr[N*20];
            struct data {int to,next;}e[N*2];
            int n,m,a[N],head[N],edge_cnt;
            int dep[N],son[N],f[N],bl[N],sz;
            int root[N],cntt,hash[N],hash_tot;
            int last;
        public:
            inline int read()
            {
                int x=0,f=1;char c=getchar();
                while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
                while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}        
                return x*f;
            }
            inline void add(int u,int v)
            {
                e[++edge_cnt].to=v;e[edge_cnt].next=head[u];head[u]=edge_cnt;
                e[++edge_cnt].to=u;e[edge_cnt].next=head[v];head[v]=edge_cnt;
            }
            void init()
            {
                n=read();m=read();
                for(int i=1;i<=n;i++) a[i]=read(),hash[i]=a[i];
                int u,v;
                for(int i=1;i<n;i++)
                {
                    scanf("%d%d",&u,&v);
                    add(u,v);
                }
            }
            inline void tree_insert(int pre,int & now,int l,int r,int k)
            {
                tr[now=++cntt].cnt=tr[pre].cnt+1;
                if(l==r) return;
                int mid=l+r>>1;
                if(k<=mid) 
                {
                    tr[now].r=tr[pre].r;
                    tree_insert(tr[pre].l,tr[now].l,l,mid,k);
                }
                else 
                {
                    tr[now].l=tr[pre].l;
                    tree_insert(tr[pre].r,tr[now].r,mid+1,r,k); 
                }
            }
            inline void dfs1(int x,int fa)
            {
                son[x]++;
                tree_insert(root[fa],root[x],1,hash_tot,hash[x]);    
                for(int i=head[x];i;i=e[i].next)
                {
                    if(e[i].to==fa) continue;
                    f[e[i].to]=x;
                    dep[e[i].to]=dep[x]+1;
                    dfs1(e[i].to,x);
                    son[x]+=son[e[i].to];
                }
            }
            inline void dfs2(int x,int chain)//给重链编号 
            {
                bl[x]=chain;
                int m=0;
                for(int i=head[x];i;i=e[i].next)
                {
                    if(e[i].to==f[x]) continue;
                    if(son[e[i].to]>son[m]) m=e[i].to;
                }
                if(!m) return;
                dfs2(m,chain);
                for(int i=head[x];i;i=e[i].next)
                {
                    if(e[i].to==f[x]||e[i].to==m) continue;
                     dfs2(e[i].to,e[i].to);
                } 
            }
            inline int getlca(int u,int v)//求lca,本函数+上面2个函数为树链剖分求LCA 
            {
                while(bl[u]!=bl[v])
                {
                    if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
                    u=f[bl[u]];
                }
                if(dep[u]<dep[v]) return u;
                return v;
            }
            void discrete()
            {
                sort(a+1,a+n+1);
                hash_tot=unique(a+1,a+n+1)-(a+1);
                for(int i=1;i<=n;i++) hash[i]=lower_bound(a+1,a+hash_tot+1,hash[i])-a;
            }
            inline int tree_query(int x,int y,int lca,int fa_lca,int l,int r,int k)
            {
                if(l==r) return a[l];
                int mid=l+r>>1,tmp=tr[tr[x].l].cnt+tr[tr[y].l].cnt-tr[tr[lca].l].cnt-tr[tr[fa_lca].l].cnt;
                if(k<=tmp) tree_query(tr[x].l,tr[y].l,tr[lca].l,tr[fa_lca].l,l,mid,k);
                else tree_query(tr[x].r,tr[y].r,tr[lca].r,tr[fa_lca].r,mid+1,r,k-tmp);
            }
            void init2()
            {
                int u,v,k;
                for(int i=1;i<=m;i++)
                {
                    u=read();v=read();k=read();
                    u^=last;
                    int lca=getlca(u,v);
                    last=tree_query(root[u],root[v],root[lca],root[f[lca]],1,hash_tot,k);
                    if(i!=m )printf("%d
    ",last);
                    else printf("%d",last);
                }
            }
            void work()
            {
                init();
                discrete();
                dfs1(1,0);
                dfs2(1,1);
                init2();
            }
            
    }a;
    int main()
    {
        a.work();
    }

    初做犯了一个很蠢的错误:最后一行不输出换行,楞是没看见

    不读完题,第二次了。

  • 相关阅读:
    LDAP安装配置(windows)
    chrome postman插件手动安装
    mabatis insert into on duplicate key
    ZOJ 3641 <并查集+STL>
    ZOJ 3633 <rmq 重点在于转化>
    POJ 2817 状态DP 字符串找最多的重复
    POJ 2771 简单二分图匹配
    POJ 1149 最大流<建图> PIGS
    POJ 3692 二分图最大独立点集
    POJ 2239 简单的二分图求最大匹配
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6383854.html
Copyright © 2011-2022 走看看