BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)

谁践踏了优雅 2021-09-29 17:46 451阅读 0赞

传送门

完了今天才知道原来线段树的动态开点和主席树是不一样的啊

我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和

然后有了宗教信仰的限制该怎么做呢?

先考虑暴力,对每一个信仰建一棵线段树

然而必然会MLE

于是我们只能动态开点

说一下我自己的理解吧,动态开点就是把那些建树过程中没有用的节点删去,以此来节省空间

比如当$sum[p]=0$时,直接删去点$p$

具体实现还是参考一下代码吧

  1. 1 // luogu-judger-enable-o2
  2. 2 //minamoto
  3. 3 #include<bits/stdc++.h>
  4. 4 #define N 300005
  5. 5 using namespace std;
  6. 6 template<class T>inline bool cmax(T&a,const T&b){
  7. return a<b?a=b,1:0;}
  8. 7 inline int read(){
  9. 8 #define num ch-'0'
  10. 9 char ch;bool flag=0;int res;
  11. 10 while(!isdigit(ch=getchar()))
  12. 11 (ch=='-')&&(flag=true);
  13. 12 for(res=num;isdigit(ch=getchar());res=res*10+num);
  14. 13 (flag)&&(res=-res);
  15. 14 #undef num
  16. 15 return res;
  17. 16 }
  18. 17 int L[N<<2],R[N<<2],mx[N<<2],sum[N<<2];
  19. 18 int sz[N],fa[N],son[N],dfn[N],rk[N],d[N],top[N],val[N],c[N];
  20. 19 int ver[N<<1],head[N],Next[N<<1],yval[N],yc[N];
  21. 20 int rt[N];
  22. 21 int n,m,num,tot,cnt;
  23. 22 inline void add(int u,int v){
  24. 23 ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
  25. 24 ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
  26. 25 }
  27. 26 void dfs1(int u){
  28. 27 sz[u]=1,d[u]=d[fa[u]]+1;
  29. 28 for(int i=head[u];i;i=Next[i]){
  30. 29 if(ver[i]==fa[u]) continue;
  31. 30 int v=ver[i];
  32. 31 fa[v]=u;
  33. 32 dfs1(v);
  34. 33 sz[u]+=sz[v];
  35. 34 if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
  36. 35 }
  37. 36 }
  38. 37 void dfs2(int u){
  39. 38 if(!top[u]) top[u]=u;
  40. 39 dfn[u]=++num,rk[num]=u;
  41. 40 if(!son[u]) return;
  42. 41 top[son[u]]=top[u],dfs2(son[u]);
  43. 42 for(int i=head[u];i;i=Next[i]){
  44. 43 int v=ver[i];
  45. 44 if(v!=fa[u]&&v!=son[u]) dfs2(v);
  46. 45 }
  47. 46 }
  48. 47 void update(int p){
  49. 48 mx[p]=max(mx[L[p]],mx[R[p]]);
  50. 49 sum[p]=sum[L[p]]+sum[R[p]];
  51. 50 }
  52. 51 void modify(int &p,int l,int r,int k,int v){
  53. 52 if(!p) p=++cnt;
  54. 53 if(l>=r){
  55. 54 mx[p]=sum[p]=v;return;
  56. 55 }
  57. 56 int mid=(l+r)>>1;
  58. 57 if(k<=mid) modify(L[p],l,mid,k,v);
  59. 58 else modify(R[p],mid+1,r,k,v);
  60. 59 update(p);
  61. 60 if(sum[p]==0) p=0;
  62. 61 }
  63. 62 int askmax(int p,int l,int r,int ql,int qr){
  64. 63 if(!p) return -1;
  65. 64 if(ql<=l&&qr>=r) return mx[p];
  66. 65 int mid=(l+r)>>1,val=-1;
  67. 66 if(ql<=mid) cmax(val,askmax(L[p],l,mid,ql,qr));
  68. 67 if(qr>mid) cmax(val,askmax(R[p],mid+1,r,ql,qr));
  69. 68 return val;
  70. 69 }
  71. 70 int asksum(int p,int l,int r,int ql,int qr){
  72. 71 if(!p) return 0;
  73. 72 if(ql<=l&&qr>=r) return sum[p];
  74. 73 int mid=(l+r)>>1,val=0;
  75. 74 if(ql<=mid) val+=asksum(L[p],l,mid,ql,qr);
  76. 75 if(qr>mid) val+=asksum(R[p],mid+1,r,ql,qr);
  77. 76 return val;
  78. 77 }
  79. 78 int path_max(int u,int v){
  80. 79 int ans=-1;
  81. 80 int xz=yc[u];
  82. 81 while(top[u]!=top[v]){
  83. 82 if(d[top[u]]<d[top[v]]) swap(u,v);
  84. 83 cmax(ans,askmax(rt[xz],1,num,dfn[top[u]],dfn[u]));
  85. 84 u=fa[top[u]];
  86. 85 }
  87. 86 if(d[u]<d[v]) swap(u,v);
  88. 87 cmax(ans,askmax(rt[xz],1,num,dfn[v],dfn[u]));
  89. 88 return ans;
  90. 89 }
  91. 90 int path_sum(int u,int v){
  92. 91 int ans=0;
  93. 92 int xz=yc[u];
  94. 93 while(top[u]!=top[v]){
  95. 94 if(d[top[u]]<d[top[v]]) swap(u,v);
  96. 95 ans+=asksum(rt[xz],1,num,dfn[top[u]],dfn[u]);
  97. 96 u=fa[top[u]];
  98. 97 }
  99. 98 if(d[u]<d[v]) swap(u,v);
  100. 99 ans+=asksum(rt[xz],1,num,dfn[v],dfn[u]);
  101. 100 return ans;
  102. 101 }
  103. 102 int main(){
  104. 103 //freopen("testdata.in","r",stdin);
  105. 104 int n,q;
  106. 105 n=read(),q=read();
  107. 106 for(int i=1;i<=n;++i)
  108. 107 yval[i]=read(),yc[i]=read();
  109. 108 for(int i=1;i<n;++i){
  110. 109 int u=read(),v=read();
  111. 110 add(u,v);
  112. 111 }
  113. 112 dfs1(1),dfs2(1);
  114. 113 for(int i=1;i<=n;++i)
  115. 114 modify(rt[yc[rk[i]]],1,num,i,yval[rk[i]]);
  116. 115 while(q--){
  117. 116 char s[10];int x,y;
  118. 117 scanf("%s",s);
  119. 118 x=read(),y=read();
  120. 119 switch(s[1]){
  121. 120 case 'C':{
  122. 121 modify(rt[yc[x]],1,num,dfn[x],0);
  123. 122 yc[x]=y;
  124. 123 modify(rt[yc[x]],1,num,dfn[x],yval[x]);
  125. 124 break;
  126. 125 }
  127. 126 case 'W':{
  128. 127 yval[x]=y;
  129. 128 modify(rt[yc[x]],1,num,dfn[x],yval[x]);
  130. 129 break;
  131. 130 }
  132. 131 case 'S':{
  133. 132 printf("%d\n",path_sum(x,y));
  134. 133 break;
  135. 134 }
  136. 135 case 'M':{
  137. 136 printf("%d\n",path_max(x,y));
  138. 137 break;
  139. 138 }
  140. 139 }
  141. 140 }
  142. 141 return 0;
  143. 142 }

转载于:https://www.cnblogs.com/bztMinamoto/p/9398077.html

发表评论

表情:
评论列表 (有 0 条评论,451人围观)

还没有评论,来说两句吧...

相关阅读

    相关 BZOJ1095 动态分治()

    题意: 操作1.修改一个点的颜色(黑白互换) 操作2.询问所有黑色点之间最远距离   点分树:当我们可以形如点分治一样的统计答案,即每次确定一个重心,然后计算他们子树之

    相关 [bzoj3531]旅行

    对其树剖,然后对于同一种宗教开一棵动态开点的区间线段树,维护区间max和sum,像普通的树剖一样处理即可。 ![ContractedBlock.gif][] ![Expand