题目链接

第一种方法,dfs序上建可持久化线段树,然后询问的时候把两点之间的所有树链扒出来做差。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=1e5+,inf=0x3f3f3f3f;
  5. int hd[N],ne,n,n2,m,fa[N],son[N],siz[N],dep[N],top[N],dfn[N],rnk[N],tot,rt[N],ls[N*],rs[N*],val[N*],tot2,a[N],b[N],ql[],qr[],nl,nr;
  6. struct E {int v,nxt;} e[N<<];
  7. void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
  8. void dfs1(int u,int f,int d) {
  9. fa[u]=f,son[u]=,siz[u]=,dep[u]=d;
  10. for(int i=hd[u]; ~i; i=e[i].nxt) {
  11. int v=e[i].v;
  12. if(v==fa[u])continue;
  13. dfs1(v,u,d+),siz[u]+=siz[v];
  14. if(siz[v]>siz[son[u]])son[u]=v;
  15. }
  16. }
  17. void dfs2(int u,int tp) {
  18. top[u]=tp,dfn[u]=++tot,rnk[tot]=u;
  19. if(son[u])dfs2(son[u],tp);
  20. for(int i=hd[u]; ~i; i=e[i].nxt) {
  21. int v=e[i].v;
  22. if(v==fa[u]||v==son[u])continue;
  23. dfs2(v,v);
  24. }
  25. }
  26. #define mid ((l+r)>>1)
  27. void upd(int& u,int v,int x,int l=,int r=n2) {
  28. if(!u)u=++tot2;
  29. val[u]=val[v]+;
  30. if(l==r)return;
  31. if(x<=mid)upd(ls[u],ls[v],x,l,mid),rs[u]=rs[v];
  32. else upd(rs[u],rs[v],x,mid+,r),ls[u]=ls[v];
  33. }
  34. int ask(int u,int v,int k) {
  35. for(nl=nr=; top[u]!=top[v]; u=fa[top[u]]) {
  36. if(dep[top[u]]<dep[top[v]])swap(u,v);
  37. ql[nl++]=rt[dfn[top[u]]-],qr[nr++]=rt[dfn[u]];
  38. }
  39. if(dep[u]<dep[v])swap(u,v);
  40. ql[nl++]=rt[dfn[v]-],qr[nr++]=rt[dfn[u]];
  41. int l=,r=n2;
  42. while(l<r) {
  43. int cnt=;
  44. for(int i=; i<nr; ++i)cnt+=val[ls[qr[i]]];
  45. for(int i=; i<nl; ++i)cnt-=val[ls[ql[i]]];
  46. if(k<=cnt) {
  47. for(int i=; i<nr; ++i)qr[i]=ls[qr[i]];
  48. for(int i=; i<nl; ++i)ql[i]=ls[ql[i]];
  49. r=mid;
  50. } else {
  51. k-=cnt;
  52. for(int i=; i<nr; ++i)qr[i]=rs[qr[i]];
  53. for(int i=; i<nl; ++i)ql[i]=rs[ql[i]];
  54. l=mid+;
  55. }
  56. }
  57. return l;
  58. }
  59. int main() {
  60. memset(hd,-,sizeof hd),ne=;
  61. scanf("%d%d",&n,&m);
  62. for(int i=; i<=n; ++i)scanf("%d",&a[i]);
  63. for(int i=; i<=n; ++i)b[i-]=a[i];
  64. sort(b,b+n),n2=unique(b,b+n)-b;
  65. for(int i=; i<=n; ++i)a[i]=(lower_bound(b,b+n2,a[i])-b)+;
  66. for(int i=; i<n; ++i) {
  67. int u,v;
  68. scanf("%d%d",&u,&v);
  69. addedge(u,v),addedge(v,u);
  70. }
  71. tot=,dfs1(,,),dfs2(,);
  72. memset(rt,,sizeof rt),tot2=;
  73. for(int i=; i<=n; ++i)upd(rt[i],rt[i-],a[rnk[i]],,n2);
  74. for(int last=; m--;) {
  75. int u,v,k;
  76. scanf("%d%d%d",&u,&v,&k),u^=last;
  77. int ans=b[ask(u,v,k)-];
  78. printf("%d\n",ans),last=ans;
  79. }
  80. return ;
  81. }

仔细一想这样似乎麻烦了点。因为没有修改操作,我们可以直接用子结点继承父节点的方式来建线段树,然后查询的时候,用u,v的线段树减去lca的线段树再减去lca父节点的线段树即可。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=1e5+,inf=0x3f3f3f3f;
  5. int hd[N],ne,n,n2,m,fa[N],son[N],siz[N],dep[N],top[N],dfn[N],rnk[N],tot,rt[N],ls[N*],rs[N*],val[N*],tot2,a[N],b[N],ql[],qr[],nl,nr;
  6. struct E {int v,nxt;} e[N<<];
  7. void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
  8. void dfs1(int u,int f,int d) {
  9. fa[u]=f,son[u]=,siz[u]=,dep[u]=d;
  10. for(int i=hd[u]; ~i; i=e[i].nxt) {
  11. int v=e[i].v;
  12. if(v==fa[u])continue;
  13. dfs1(v,u,d+),siz[u]+=siz[v];
  14. if(siz[v]>siz[son[u]])son[u]=v;
  15. }
  16. }
  17. void dfs2(int u,int tp) {
  18. top[u]=tp,dfn[u]=++tot,rnk[tot]=u;
  19. if(son[u])dfs2(son[u],tp);
  20. for(int i=hd[u]; ~i; i=e[i].nxt) {
  21. int v=e[i].v;
  22. if(v==fa[u]||v==son[u])continue;
  23. dfs2(v,v);
  24. }
  25. }
  26. #define mid ((l+r)>>1)
  27. void upd(int& u,int v,int x,int l=,int r=n2) {
  28. if(!u)u=++tot2;
  29. val[u]=val[v]+;
  30. if(l==r)return;
  31. if(x<=mid)upd(ls[u],ls[v],x,l,mid),rs[u]=rs[v];
  32. else upd(rs[u],rs[v],x,mid+,r),ls[u]=ls[v];
  33. }
  34. void dfs3(int u) {
  35. upd(rt[u],rt[fa[u]],a[u]);
  36. for(int i=hd[u]; ~i; i=e[i].nxt) {
  37. int v=e[i].v;
  38. if(v==fa[u])continue;
  39. dfs3(v);
  40. }
  41. }
  42. int lca(int u,int v) {
  43. for(; top[u]!=top[v]; u=fa[top[u]])if(dep[top[u]]<dep[top[v]])swap(u,v);
  44. return dep[u]<dep[v]?u:v;
  45. }
  46. int ask(int u,int v,int w1,int w2,int k,int l=,int r=n2) {
  47. if(l==r)return l;
  48. int cnt=val[ls[u]]+val[ls[v]]-val[ls[w1]]-val[ls[w2]];
  49. return k<=cnt?ask(ls[u],ls[v],ls[w1],ls[w2],k,l,mid):ask(rs[u],rs[v],rs[w1],rs[w2],k-cnt,mid+,r);
  50. }
  51. int main() {
  52. memset(hd,-,sizeof hd),ne=;
  53. scanf("%d%d",&n,&m);
  54. for(int i=; i<=n; ++i)scanf("%d",&a[i]);
  55. for(int i=; i<=n; ++i)b[i-]=a[i];
  56. sort(b,b+n),n2=unique(b,b+n)-b;
  57. for(int i=; i<=n; ++i)a[i]=(lower_bound(b,b+n2,a[i])-b)+;
  58. for(int i=; i<n; ++i) {
  59. int u,v;
  60. scanf("%d%d",&u,&v);
  61. addedge(u,v),addedge(v,u);
  62. }
  63. tot=,dfs1(,,),dfs2(,);
  64. memset(rt,,sizeof rt),tot2=;
  65. dfs3();
  66. for(int last=; m--;) {
  67. int u,v,k;
  68. scanf("%d%d%d",&u,&v,&k),u^=last;
  69. int w=lca(u,v);
  70. int ans=b[ask(rt[u],rt[v],rt[w],rt[fa[w]],k)-];
  71. printf("%d\n",ans),last=ans;
  72. }
  73. return ;
  74. }

然后我又测试了倍增和RMQ求LCA的方法,发现居然还不如dfs序+可持久化线段树的方法快~~毕竟倍增和RMQ预处理的时间和空间复杂度都是$O(nlogn)$,而树剖只需要$O(n)$,而且查询速度也比较快。

倍增:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=1e5+,inf=0x3f3f3f3f;
  5. int hd[N],ne,n,n2,m,fa[N][],dep[N],rt[N],ls[N*],rs[N*],val[N*],tot2,a[N],b[N];
  6. struct E {int v,nxt;} e[N<<];
  7. void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
  8. #define mid ((l+r)>>1)
  9. void upd(int& u,int v,int x,int l=,int r=n2) {
  10. if(!u)u=++tot2;
  11. val[u]=val[v]+;
  12. if(l==r)return;
  13. if(x<=mid)upd(ls[u],ls[v],x,l,mid),rs[u]=rs[v];
  14. else upd(rs[u],rs[v],x,mid+,r),ls[u]=ls[v];
  15. }
  16. void dfs(int u,int f,int d) {
  17. fa[u][]=f,dep[u]=d,upd(rt[u],rt[fa[u][]],a[u]);
  18. for(int i=; i<; ++i)fa[u][i]=fa[fa[u][i-]][i-];
  19. for(int i=hd[u]; ~i; i=e[i].nxt) {
  20. int v=e[i].v;
  21. if(v==fa[u][])continue;
  22. dfs(v,u,d+);
  23. }
  24. }
  25. int lca(int u,int v) {
  26. if(dep[u]<dep[v])swap(u,v);
  27. for(int i=; dep[u]!=dep[v]; --i)if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
  28. if(u==v)return u;
  29. for(int i=; i>=; --i)if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
  30. return fa[u][];
  31. }
  32. int ask(int u,int v,int w1,int w2,int k,int l=,int r=n2) {
  33. if(l==r)return l;
  34. int cnt=val[ls[u]]+val[ls[v]]-val[ls[w1]]-val[ls[w2]];
  35. return k<=cnt?ask(ls[u],ls[v],ls[w1],ls[w2],k,l,mid):ask(rs[u],rs[v],rs[w1],rs[w2],k-cnt,mid+,r);
  36. }
  37. int main() {
  38. memset(hd,-,sizeof hd),ne=;
  39. scanf("%d%d",&n,&m);
  40. for(int i=; i<=n; ++i)scanf("%d",&a[i]);
  41. for(int i=; i<=n; ++i)b[i-]=a[i];
  42. sort(b,b+n),n2=unique(b,b+n)-b;
  43. for(int i=; i<=n; ++i)a[i]=(lower_bound(b,b+n2,a[i])-b)+;
  44. for(int i=; i<n; ++i) {
  45. int u,v;
  46. scanf("%d%d",&u,&v);
  47. addedge(u,v),addedge(v,u);
  48. }
  49. memset(rt,,sizeof rt),tot2=;
  50. dfs(,,);
  51. for(int last=; m--;) {
  52. int u,v,k;
  53. scanf("%d%d%d",&u,&v,&k),u^=last;
  54. int w=lca(u,v);
  55. int ans=b[ask(rt[u],rt[v],rt[w],rt[fa[w][]],k)-];
  56. printf("%d\n",ans),last=ans;
  57. }
  58. return ;
  59. }

RMQ:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=1e5+,inf=0x3f3f3f3f;
  5. int hd[N],ne,n,n2,m,fa[N],dep[N],pos[N],ST[N<<][],Log[N<<],tot,rt[N],ls[N*],rs[N*],val[N*],tot2,a[N],b[N];
  6. struct E {int v,nxt;} e[N<<];
  7. void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
  8. #define mid ((l+r)>>1)
  9. void upd(int& u,int v,int x,int l=,int r=n2) {
  10. if(!u)u=++tot2;
  11. val[u]=val[v]+;
  12. if(l==r)return;
  13. if(x<=mid)upd(ls[u],ls[v],x,l,mid),rs[u]=rs[v];
  14. else upd(rs[u],rs[v],x,mid+,r),ls[u]=ls[v];
  15. }
  16. void dfs(int u,int f,int d) {
  17. fa[u]=f,dep[u]=d,ST[++tot][]=u,pos[u]=tot,upd(rt[u],rt[fa[u]],a[u]);
  18. for(int i=hd[u]; ~i; i=e[i].nxt) {
  19. int v=e[i].v;
  20. if(v==fa[u])continue;
  21. dfs(v,u,d+),ST[++tot][]=u;
  22. }
  23. }
  24. bool cmp(int a,int b) {return dep[a]<dep[b];}
  25. void initST() {
  26. for(int j=; j<; ++j)
  27. for(int i=; i+(<<j)-<=tot; ++i)
  28. ST[i][j]=min(ST[i][j-],ST[i+(<<(j-))][j-],cmp);
  29. }
  30. int lca(int u,int v) {
  31. int l=pos[u],r=pos[v];
  32. if(l>r)swap(l,r);
  33. int i=Log[r-l+];
  34. return min(ST[l][i],ST[r-(<<i)+][i],cmp);
  35. }
  36. int ask(int u,int v,int w1,int w2,int k,int l=,int r=n2) {
  37. if(l==r)return l;
  38. int cnt=val[ls[u]]+val[ls[v]]-val[ls[w1]]-val[ls[w2]];
  39. return k<=cnt?ask(ls[u],ls[v],ls[w1],ls[w2],k,l,mid):ask(rs[u],rs[v],rs[w1],rs[w2],k-cnt,mid+,r);
  40. }
  41. int main() {
  42. for(int i=; i<(N<<); ++i)Log[i]=log2(i+0.5);
  43. memset(hd,-,sizeof hd),ne=;
  44. scanf("%d%d",&n,&m);
  45. for(int i=; i<=n; ++i)scanf("%d",&a[i]);
  46. for(int i=; i<=n; ++i)b[i-]=a[i];
  47. sort(b,b+n),n2=unique(b,b+n)-b;
  48. for(int i=; i<=n; ++i)a[i]=(lower_bound(b,b+n2,a[i])-b)+;
  49. for(int i=; i<n; ++i) {
  50. int u,v;
  51. scanf("%d%d",&u,&v);
  52. addedge(u,v),addedge(v,u);
  53. }
  54. memset(rt,,sizeof rt),tot2=;
  55. dfs(,,),initST();
  56. for(int last=; m--;) {
  57. int u,v,k;
  58. scanf("%d%d%d",&u,&v,&k),u^=last;
  59. int w=lca(u,v);
  60. int ans=b[ask(rt[u],rt[v],rt[w],rt[fa[w]],k)-];
  61. printf("%d\n",ans),last=ans;
  62. }
  63. return ;
  64. }

BZOJ - 2588 Spoj 10628. Count on a tree (可持久化线段树+LCA/树链剖分)的更多相关文章

  1. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  2. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  3. Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 2588: Spoj 10628. Count on a tree Time Limit ...

  4. BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )

    Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...

  5. Bzoj 2588 Spoj 10628. Count on a tree(树链剖分LCA+主席树)

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MB Description 给定一棵N个节点的树,每个点 ...

  6. bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)

    Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 7669  Solved: 1894[Submi ...

  7. 主席树 || 可持久化线段树 || LCA || BZOJ 2588: Spoj 10628. Count on a tree || Luogu P2633 Count on a tree

    题面: Count on a tree 题解: 主席树维护每个节点到根节点的权值出现次数,大体和主席树典型做法差不多,对于询问(X,Y),答案要计算ans(X)+ans(Y)-ans(LCA(X,Y) ...

  8. BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

    分析:树上第k小,然后我想说的是主席树并不局限于线性表 详细分析请看http://www.cnblogs.com/rausen/p/4006116.html,讲的很好, 然后因为这个熟悉了主席树,真是 ...

  9. ●BZOJ 2588 Spoj 10628. Count on a tree

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2588 题解: 主席树,在线,(求LCA)感觉主席树真的好厉害...在原树上建主席树.即对于原 ...

随机推荐

  1. spring 异步处理request

    转自:http://blog.csdn.net/u012410733/article/details/52124333Spring MVC 3.2开始引入Servlet 3中的基于异步的处理reque ...

  2. 请求json和xml数据时的方式

    当请求xml数据时,直接通过NSMutableData接收后解析, NSURL *url = [NSURL URLWithString:PATH]; _receiveData = [[NSMutabl ...

  3. 【LeetCode】【动态规划】Edit Distance

    描述 Given two words word1 and word2, find the minimum number of operations required to convert word1  ...

  4. 吐槽 坑爹的MySQL安装路径选择

    一般再windows下面安装MySQL我们都会选择msi安装模式,然而安装最新版的MySQL(mysql-installer-community-5.7.11.0.msi 下载地址)发现MySQL默认 ...

  5. tcp/ip 中的分组和分片

    osi 大家应该都知道osi七层模型吧,物理层 链路层 网络层 传输层 会话层 表示层 应用层ip 属于网络层,tcp 属于传输层,你可以把每一层想像成粽子的粽叶,包裹了七层的粽子最外面的就是物理层, ...

  6. TypeScript手册1 - 基本类型和接口

    基本类型 像基本的JavaScript一样,TypeScript支持numbers, strings, structures, boolean等基本类型,而扩展的enum等类型,为编程提供了更多帮助. ...

  7. ASP.NET5 MVC6 利用Middleware 创建可访问HttpContext 的业务类工厂。(代替HttpContext.Current)

    我们的目标是在后台业务处理类中,能够很容易的取得用户信息或者其它HTTP请求相关的信息. 所以,首先我们需要一个存储这些信息的类: public class RequestData { public ...

  8. R语言学习笔记(1)

    第一章:R语言介绍 一 R的使用 1 R是一种区分大小写的解释型语言.R语句由函数和赋值构成.R使用<-作为赋值符号.例如: x<-rnorm(5) 创建了一个名为x的向量对象,它包含5个 ...

  9. UVA 12307 Smallest Enclosing Rectangle(旋转卡壳)

    题意:给你一些点,找出两个可以包含所有点的矩形,一个保证矩形面积最小,一个保证矩形周长最小,输出两个最小值 题解:首先根据所有点求一个凸包,再在这个凸包上枚举每条边,作为矩形的一条边(这样可以保证最小 ...

  10. 【转】Android ImageView圆形头像

    Android ImageView圆形头像 图片完全解析 我们在做项目的时候会用到圆形的图片,比如用户头像,类似QQ.用户在用QQ更换头像的时候,上传的图片都是矩形的,但显示的时候确是圆形的. 原理: ...