[关闭]
@xiaoziyao 2021-04-20T18:07:04.000000Z 字数 3398 阅读 1028

P7518 [省选联考 2021 A/B 卷] 宝石解题报告

解题报告


P7518 [省选联考 2021 A/B 卷] 宝石解题报告:

更好的阅读体验

题意

给定一颗个点的带点权的树,以及一个长度为的匹配序列,(点权与序列的值域为),次询问,每次询问的有向路径与匹配序列匹配的最长前缀的长度。

分析

考场写了一个5k的树分块的做法,然后被卡常卡成就很离谱。

(该部分可略过)
在树上撒个关键点,每个点与其祖先里的关键点距离为,然后发现可以把询问的路径分成个散块和个整块,散块暴力跳(记得把到另一端的路径反向,我因为反向调了一个多小时),整块可以预处理第个关键点跳到祖先关键点这一条链,从位置开始匹配能匹配到哪里,不难发现(我想了十几分钟)可以用并查集维护所有位置同时进行匹配,同样还要反过来做一遍。
具体地,可以把整块对应的链上权值序列当成一个普通的序列,与长度为m的串进行匹配,然后对于每个位置可以维护它在匹配的过程中到了哪一个位置,不难发现把相同的位置在匹配的过程中会不断合并,那么直接上并查集就好了。

然后发现的树上倍增好想好写的一批。

首先进行一次转化,把点权转化为在序列中的位置,这样好做一些。

考虑预处理向上跳第一个点权为的点的位置,这是一个经典问题,在树上用主席树完成就好了,时空复杂度均为

然后再按照树上倍增的套路预处理一个表示向上跳,从当前点权匹配到的位置,以及表示向上跳,从当前点权反向匹配到的位置。我们首先用主席树帮忙处理出,然后直接合并就好了。

对于询问,设,考虑让跳到第一个点权为的点开始匹配(需要特判一下跳出这一条链的情况),然后用树上倍增暴力跳数组直到跳出这一条链。

之后,我们发现不能进行类似的操作,因为我们不知道结尾的点权为多少,不难发现答案具有可二分性,直接二分最后的位置,然后按照上面的方法跳就好了。

时间复杂度:

代码

常数似乎很大。

  1. #include<stdio.h>
  2. const int maxm=50005,maxn=200005,maxe=maxn<<1,maxk=25;
  3. int n,m,c,e,q,tot;
  4. int p[maxm],w[maxn],start[maxn],to[maxe],then[maxe],fore[maxn][maxk],dep[maxn],pos[maxm];
  5. int lc[maxn*maxk],rc[maxn*maxk],res[maxn*maxk],rt[maxn],inc[maxn][maxk],dec[maxn][maxk];
  6. inline void add(int x,int y){
  7. then[++e]=start[x],start[x]=e,to[e]=y;
  8. }
  9. void build(int l,int r,int &now){
  10. if(now==0)
  11. now=++tot;
  12. if(l==r){
  13. res[now]=-1;
  14. return ;
  15. }
  16. int mid=(l+r)>>1;
  17. build(l,mid,lc[now]),build(mid+1,r,rc[now]);
  18. }
  19. inline int newnode(int x){
  20. tot++,lc[tot]=lc[x],rc[tot]=rc[x],res[tot]=res[x];
  21. return tot;
  22. }
  23. void update(int l,int r,int &now,int pos,int v){
  24. now=newnode(now);
  25. if(l==r){
  26. res[now]=v;
  27. return ;
  28. }
  29. int mid=(l+r)>>1;
  30. if(pos<=mid)
  31. update(l,mid,lc[now],pos,v);
  32. else update(mid+1,r,rc[now],pos,v);
  33. }
  34. int query(int l,int r,int now,int pos){
  35. if(l==r)
  36. return res[now];
  37. int mid=(l+r)>>1;
  38. if(pos<=mid)
  39. return query(l,mid,lc[now],pos);
  40. return query(mid+1,r,rc[now],pos);
  41. }
  42. void dfs(int x,int last){
  43. dep[x]=dep[last]+1,fore[x][0]=last,rt[x]=rt[last];
  44. if(w[x]!=-1)
  45. update(1,c,rt[x],w[x],x);
  46. inc[x][0]=(w[x]==-1||w[x]==c)? -1:query(1,c,rt[x],w[x]+1);
  47. dec[x][0]=(w[x]==-1||w[x]==1)? -1:query(1,c,rt[x],w[x]-1);
  48. for(int i=1;i<=20;i++){
  49. fore[x][i]=fore[fore[x][i-1]][i-1];
  50. inc[x][i]=inc[x][i-1]==-1? -1:inc[inc[x][i-1]][i-1];
  51. dec[x][i]=dec[x][i-1]==-1? -1:dec[dec[x][i-1]][i-1];
  52. }
  53. for(int i=start[x];i;i=then[i]){
  54. int y=to[i];
  55. if(y==last)
  56. continue;
  57. dfs(y,x);
  58. }
  59. }
  60. int lca(int a,int b){
  61. if(dep[a]<dep[b])
  62. a+=b,b=a-b,a-=b;
  63. for(int i=20;i>=0;i--)
  64. if(dep[fore[a][i]]>=dep[b])
  65. a=fore[a][i];
  66. if(a==b)
  67. return a;
  68. for(int i=20;i>=0;i--)
  69. if(fore[a][i]!=fore[b][i])
  70. a=fore[a][i],b=fore[b][i];
  71. return fore[a][0];
  72. }
  73. int check(int x,int z,int now,int goal){
  74. x=query(1,c,rt[x],goal);
  75. if(x==-1||dep[x]<dep[z])
  76. return 0;
  77. for(int i=20;i>=0;i--)
  78. if(dec[x][i]!=-1&&dep[dec[x][i]]>dep[z])
  79. x=dec[x][i];
  80. return w[x]<=now;
  81. }
  82. int main(){
  83. scanf("%d%d%d",&n,&m,&c);
  84. for(int i=1;i<=m;i++)
  85. pos[i]=-1;
  86. for(int i=1;i<=c;i++)
  87. scanf("%d",&p[i]),pos[p[i]]=i;
  88. for(int i=1;i<=n;i++)
  89. scanf("%d",&w[i]),w[i]=pos[w[i]];
  90. for(int i=1;i<n;i++){
  91. int x,y;
  92. scanf("%d%d",&x,&y);
  93. add(x,y),add(y,x);
  94. }
  95. build(1,c,rt[0]),dfs(1,0);
  96. scanf("%d",&q);
  97. while(q--){
  98. int x,y,z,res=0;
  99. scanf("%d%d",&x,&y),z=lca(x,y);
  100. x=query(1,c,rt[x],1);
  101. if(x!=-1&&dep[x]>=dep[z]){
  102. for(int i=20;i>=0;i--)
  103. if(inc[x][i]!=-1&&dep[inc[x][i]]>=dep[z])
  104. x=inc[x][i];
  105. res=w[x];
  106. }
  107. int L=res,R=c+1;
  108. while(L+1<R){
  109. int mid=(L+R)>>1;
  110. if(check(y,z,res+1,mid))
  111. L=mid;
  112. else R=mid;
  113. }
  114. printf("%d\n",L);
  115. }
  116. return 0;
  117. }

省选联考A卷全部题解可见:2021省选联考A卷解题报告

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注