[关闭]
@xiaoziyao 2020-10-13T15:14:17.000000Z 字数 3619 阅读 1074

CF1192B Dynamic Diameter解题报告

解题报告


CF1192B Dynamic Diameter解题报告:

更好的阅读体验

题意

分析

欧拉序+线段树维护好题。

对于一个直径,我们可以把它拆成两条链,此时,我们要引入一个叫欧拉序的东西:

欧拉序与dfs序很类似,对于每个结点,在进入这个结点子树时记录一遍欧拉序,每一次从儿子子树中出来时也记录一遍欧拉序。

下面给出记录欧拉序的代码:

  1. void dfs(int x,int last){
  2. q[++qs]=x,in[x]=qs;
  3. for(int i=start[x];i;i=then[i]){
  4. int y=to[i];
  5. if(y==last)
  6. continue;
  7. dfs(y,x);
  8. q[++qs]=x;
  9. }
  10. out[x]=qs;
  11. }

其中为欧拉序组成的序列,为进入子树时的欧拉序,则为出子树时的欧拉序。

这种序列有什么性质呢?

有了这个欧拉序,我们就相当于把这个树拍平了(类似于dfs序),我们来看这两个操作:

维护直径具体操作:

维护当前区间的最大深度,最小深度;维护一个深度差,表示左边是深度深的点,右边是深度浅的点,它们的最大是多少,同理维护一个深度差,表示左边是深度浅的点,右边是深度深的点,它们的最大是多少,这两个东西可以很轻松的完成维护。

然后,我们维护一个路径长度,代表左边一个深度深的点,中间一个深度浅的点(),右边一个深度深的点,它们的路径长度最长是多少。这个可以继承左右区间的,也可以用左区间的和右区间的来合并,或者用左区间的和右区间的合并。

维护上述值的代码:

  1. inline void pushup(int now){
  2. maxd[now]=max(maxd[lc[now]],maxd[rc[now]]);
  3. mind[now]=min(mind[lc[now]],mind[rc[now]]);
  4. lm[now]=max(max(lm[lc[now]],lm[rc[now]]),maxd[lc[now]]-2*mind[rc[now]]);
  5. mr[now]=max(max(mr[lc[now]],mr[rc[now]]),maxd[rc[now]]-2*mind[lc[now]]);
  6. lmr[now]=max(max(lmr[lc[now]],lmr[rc[now]]),max(lm[lc[now]]+maxd[rc[now]],maxd[lc[now]]+mr[rc[now]]));
  7. }

代码

边权很大,记得开

完整代码:

  1. #include<stdio.h>
  2. #define int long long
  3. const int maxn=100005;
  4. int n,m,w,qs,e,lastans;
  5. int start[maxn],to[maxn<<1],then[maxn<<1],worth[maxn<<1],id[maxn<<1],dis[maxn],in[maxn],out[maxn],q[maxn<<1],tid[maxn],val[maxn],maxd[maxn<<3],mind[maxn<<3],lm[maxn<<3],mr[maxn<<3],lmr[maxn<<3],lc[maxn<<3],rc[maxn<<3],lazy[maxn<<3];
  6. inline int max(int a,int b){
  7. return a>b? a:b;
  8. }
  9. inline int min(int a,int b){
  10. return a<b? a:b;
  11. }
  12. inline void add(int x,int y,int z,int i){
  13. then[++e]=start[x],start[x]=e,to[e]=y,worth[e]=z,id[e]=i;
  14. }
  15. void dfs(int x,int last){
  16. q[++qs]=x,in[x]=qs;
  17. for(int i=start[x];i;i=then[i]){
  18. int y=to[i];
  19. if(y==last)
  20. continue;
  21. dis[y]=dis[x]+worth[i];
  22. tid[id[i]]=y;
  23. dfs(y,x);
  24. q[++qs]=x;
  25. }
  26. out[x]=qs;
  27. }
  28. inline void pushup(int now){
  29. maxd[now]=max(maxd[lc[now]],maxd[rc[now]]);
  30. mind[now]=min(mind[lc[now]],mind[rc[now]]);
  31. lm[now]=max(max(lm[lc[now]],lm[rc[now]]),maxd[lc[now]]-2*mind[rc[now]]);
  32. mr[now]=max(max(mr[lc[now]],mr[rc[now]]),maxd[rc[now]]-2*mind[lc[now]]);
  33. lmr[now]=max(max(lmr[lc[now]],lmr[rc[now]]),max(lm[lc[now]]+maxd[rc[now]],maxd[lc[now]]+mr[rc[now]]));
  34. }
  35. inline void getlazy(int now,int v){
  36. maxd[now]+=v,mind[now]+=v;
  37. lm[now]-=v,mr[now]-=v;
  38. lazy[now]+=v;
  39. }
  40. inline void pushdown(int now){
  41. if(lazy[now]==0)
  42. return ;
  43. getlazy(lc[now],lazy[now]),getlazy(rc[now],lazy[now]);
  44. lazy[now]=0;
  45. }
  46. void build(int l,int r,int now){
  47. if(l==r){
  48. getlazy(now,dis[q[l]]);
  49. return ;
  50. }
  51. int mid=(l+r)>>1;
  52. lc[now]=now<<1,rc[now]=now<<1|1;
  53. build(l,mid,lc[now]),build(mid+1,r,rc[now]);
  54. pushup(now);
  55. }
  56. void update(int l,int r,int now,int L,int R,int v){
  57. if(L<=l&&r<=R){
  58. getlazy(now,v);
  59. return ;
  60. }
  61. int mid=(l+r)>>1;
  62. pushdown(now);
  63. if(L<=mid)
  64. update(l,mid,lc[now],L,R,v);
  65. if(mid<R)
  66. update(mid+1,r,rc[now],L,R,v);
  67. pushup(now);
  68. }
  69. signed main(){
  70. scanf("%lld%lld%lld",&n,&m,&w);
  71. for(int i=1;i<n;i++){
  72. int x,y,z;
  73. scanf("%lld%lld%lld",&x,&y,&z);
  74. add(x,y,z,i),add(y,x,z,i);
  75. val[i]=z;
  76. }
  77. dfs(1,0);
  78. build(1,qs,1);
  79. for(int i=1;i<=m;i++){
  80. int x,y;
  81. scanf("%lld%lld",&x,&y);
  82. x=(x+lastans)%(n-1)+1,y=(y+lastans)%w;
  83. update(1,qs,1,in[tid[x]],out[tid[x]],y-val[x]);
  84. val[x]=y,lastans=lmr[1];
  85. printf("%lld\n",lastans);
  86. }
  87. return 0;
  88. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注