题目链接

第一种方法,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. Hadoop学习基础之三:MapReduce

    现在是讨论这个问题的不错的时机,因为最近媒体上到处充斥着新的革命所谓“云计算”的信息.这种模式需要利用大量的(低端)处理器并行工作来解决计算问题.实际上,这建议利用大量的低端处理器来构建数据中心,而不 ...

  2. MySQL数据库(2)_MySQL数据库和数据库表操作语句

    一.关于数据库操作的sql语句 -- .创建数据库(在磁盘上创建一个对应的文件夹) create database [if not exists] db_name [character set xxx ...

  3. Python基础(19)_异常处理

    一.异常处理 错误和异常: 1.错误的种类: 1)语法错误:这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正 2)逻辑错误: 例如: res1=1/0  .es2=1+'str ...

  4. 前端之 JQuery

    一.基本选择器 1.#id 概述: 根据给定的ID匹配一个元素. 使用任何的元字符(如 !"#$%&'()*+,./:;<=>?@[\]^`{|}~)作为名称的文本部分, ...

  5. matlab 读取nc

    在这里做个记录,这几个是matlab用来读取.nc格式数据的函数.只是函数,参数和变量为了便于理解,取括号中的名字.   fid=netcdf.open('fname','nowriter');%打开 ...

  6. DataTable Group By或运算 Linq Aggregate的使用

    class Program { static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add(&qu ...

  7. 【TopCoder】SRM160 DIV1总结

    做了两道题之后才发现做的是DIV1,不是DIV2,DIV1的第二道题是DIV1的第三道题,果断决定第3题就不看了=.= 250分题:给定一个时间起点8:00 AM DAY 1,再给出一组时间终点,格式 ...

  8. mini2440移植uboot 2014.04(六)

    上一篇博文:<mini2440移植uboot 2014.04(五)> 代码已经上传到github上:https://github.com/qiaoyuguo/u-boot-2014.04- ...

  9. INSPIRED启示录 读书笔记 - 第12章 产品探索

    软件项目可以划分为两个阶段 探索产品阶段:弄清楚要开发什么产品(定义正确的产品) 在探索产品的阶段,产品经理负责分析各种创意,广泛收集用户需求,了解如何运用新技术,拿出产品原型并加以测试 从全局视角思 ...

  10. SQL Server 利用WITH AS递归获取层级关系数据

    WITH AS短语,也叫做子查询部分(subquery factoring),在SQL Server 2005中提供了一种解决方案,这就是公用表表达式(CTE),使用CTE,可以使SQL语句的可维护性 ...