zoukankan      html  css  js  c++  java
  • bzoj 2588 Spoj 10628. Count on a tree(主席树)

     

    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

    暴力自重。。。

     

     

    【题意】

     

           uv路径上的第k小的数。

     

    【思路】

     

           主席树,dfs序,lca,二分

           主席树就是可持久化线段树,即保留历史版本的线段树。

           为什么要保留历史版本呢?因为我们要完成对区间的查询,对于一个区间和的询问我们可以利用前缀和的思想来解决,主席树大概也是这个思路。

           我们对每一个点建一棵线段树,每一棵线段树以权值为下标,维护区间中点的数目。依次建立每一棵线段树,第i棵线段树是从第i-1棵线段树上插了个权值i而得到的。这样对于区间[l,r]的查询,我们可以通过询问T[r]T[l-1]的相应区间而得到。

           对应到这道题中,我们先离散化权值(不离散化空间还不得飞起来233),然后按照树的形态来建立每一棵线段树,每一棵线段树就是从父节点对应的线段树上拓展来的,相当于上一个版本。这样从祖先到结点路径上的线段树就是逐渐增大且只包括路径上的权值的。

           建好主席树后,对于查询(u,v),二分数的大小mid,我们就可以知道“区间”内所有小于mid的数目,为T[u].lc.sum-T[lca].lc.sum+T[v].lc.sum-T[fa[lca]].lc.sum (T[i]i对应一棵线段树,lc为左儿子,sum为对应的权值数目),如果rank比之小则缩小数的区间,使u,v,lca,fa[lca]进入左儿子,否则修改rank后进入右儿子。

     

    【代码】

     

     

      1 #include<cstdio>
      2 #include<vector>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm> 
      6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
      7 using namespace std;
      8 
      9 typedef long long ll;
     10 const int N = 1e5+5;
     11 const int M = 2*1e6+5;
     12 const int D = 18;
     13 
     14 int n,m,tot,sz,ind;
     15 int hash[N],pos[N],num[N],v[N],root[N];
     16 int sum[M],ls[M],rs[M];
     17 vector<int> g[N];
     18 
     19 ll read() {
     20     char c=getchar();
     21     ll f=1,x=0;
     22     while(!isdigit(c)) {
     23         if(c=='-')f=-1; c=getchar();
     24     }
     25     while(isdigit(c))
     26         x=x*10+c-'0', c=getchar();
     27     return x*f;
     28 }
     29 int fa[N],top[N],son[N],siz[N],dep[N];
     30 void dfs1(int u) 
     31 {
     32     siz[u]=1; son[u]=0; num[++ind]=u; pos[u]=ind;
     33     for(int i=0;i<g[u].size();i++) {
     34         int v=g[u][i];
     35         if(v!=fa[u]) {
     36             fa[v]=u;
     37             dep[v]=dep[u]+1;
     38             dfs1(v);
     39             siz[u]+=siz[v];
     40             if(siz[v]>siz[son[u]]) son[u]=v;
     41         }
     42     }
     43 }
     44 void dfs2(int u,int tp) 
     45 {
     46     top[u]=tp;
     47     if(son[u]) dfs2(son[u],tp);
     48     for(int i=0;i<g[u].size();i++) {
     49         int v=g[u][i];
     50         if(v!=fa[u] && v!=son[u]) dfs2(v,v);
     51     }
     52 }
     53 int lca(int u,int v) 
     54 {
     55     while(top[u]!=top[v]) {
     56         if(dep[top[u]]<dep[top[v]]) swap(u,v);
     57         u=fa[top[u]];
     58     }
     59     return dep[u]>dep[v]? v:u;
     60 }
     61 void update(int l,int r,int x,int &y,int num) 
     62 {
     63     y=++sz;
     64     sum[y]=sum[x]+1;
     65     if(l==r) return ;
     66     ls[y]=ls[x] ; rs[y]=rs[x]; 
     67     int mid=(l+r)>>1;
     68     if(num<=mid) update(l,mid,ls[x],ls[y],num);
     69     else update(mid+1,r,rs[x],rs[y],num);
     70 }
     71 int query(int x,int y,int rank) 
     72 {
     73     int a=x,b=y,c=lca(x,y),d=fa[c];
     74     a=root[pos[a]],b=root[pos[b]],c=root[pos[c]],d=root[pos[d]];
     75     int l=1,r=tot;
     76     while(l<r) {
     77         int mid=(l+r)>>1;
     78         int now=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
     79         if(rank<=now) r=mid,a=ls[a],b=ls[b],c=ls[c],d=ls[d];
     80         else l=mid+1,rank-=now,a=rs[a],b=rs[b],c=rs[c],d=rs[d];
     81     }
     82     return hash[l];
     83 }
     84 
     85 int main()
     86 {
     87     //freopen("in.in","r",stdin);
     88     //freopen("out.out","w",stdout); 
     89     n=read(),m=read();
     90     FOR(i,1,n) {
     91         v[i]=read(); hash[i]=v[i];
     92     }
     93     sort(hash+1,hash+n+1);
     94     tot=1;
     95     FOR(i,2,n) if(hash[i]!=hash[i-1])
     96         hash[++tot]=hash[i];
     97     FOR(i,1,n)
     98         v[i]=lower_bound(hash+1,hash+tot+1,v[i])-hash;
     99     int x,y,z;
    100     FOR(i,1,n-1) {
    101         x=read(),y=read();
    102         g[x].push_back(y);
    103         g[y].push_back(x);
    104     }
    105     dfs1(1),dfs2(1,1);
    106     FOR(i,1,n) {
    107         int t=num[i];
    108         update(1,tot,root[pos[fa[t]]],root[i],v[t]);
    109     }
    110     int lastans=0;
    111     FOR(i,1,m) {
    112         x=read(),y=read(),z=read();
    113         x^=lastans;
    114         printf("%d",lastans=query(x,y,z));
    115         if(i!=m) puts("");
    116     }
    117     return 0;
    118 }
  • 相关阅读:
    VS2008 Ajax Toolkit 控件(修正后转载)
    AD操作类[修改版]
    java中使用Rhino执行js文件中的function
    XSTL中单引号的问题
    [转]ADSearch User Property Attributes
    2008我的健身计划
    spring执行定时任务
    分页存储过程,支持多表查询,效率还行
    今天写一个读卡器程序,操作AD时的一个Exception:The authentication mechanism is unknown
    httpclient模拟windows认证
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5242457.html
Copyright © 2011-2022 走看看