题目链接

无优化版本(170行):

  1. /*
  2. 首先树剖可以维护树上的链Sum、Max
  3. 可以对每个宗教建一棵线段树,那这题就很好做了
  4. 不过10^5需要动态开点 (不明白为什么nlogn不需要回收就可以 不是每个Insert加log个节点?)
  5. 操作修改完更改原数列!盲人。。
  6. */
  7. #include<cstdio>
  8. #include<cctype>
  9. #include<algorithm>
  10. #define gc() getchar()
  11. #define now node[rt]
  12. #define lson node[rt].ls
  13. #define rson node[rt].rs
  14. const int N=1e5+5,MAXN=N*19;
  15. int n,q,cnt,H[N],Enum,to[N<<1],nxt[N<<1],fa[N],dep[N],id[N],son[N],sz[N],top[N];
  16. int idx,pos[N],W[N],rel[N],root[N],pool[MAXN];
  17. struct Seg_Tree
  18. {
  19. struct Node
  20. {
  21. int sum,maxn,ls,rs,l,r;
  22. inline void Init() {sum=maxn=l=r=ls=rs=0;}
  23. }node[MAXN];
  24. inline int new_Node() {return pool[++idx];}
  25. inline void del_Node(int rt) {now.Init(), pool[idx--]=rt;}
  26. inline void PushUp(int rt)
  27. {
  28. now.sum = node[lson].sum + node[rson].sum,
  29. now.maxn= std::max(node[lson].maxn, node[rson].maxn);
  30. }
  31. void Insert(int l,int r,int &rt,int x)
  32. {
  33. if(!rt) rt=new_Node(), now.l=l, now.r=r;
  34. if(l==r) now.sum=now.maxn=W[x];
  35. else
  36. {
  37. int m=l+r>>1;
  38. if(id[x]<=m) /*lson?0:lson=new_Node(),*/ Insert(l,m,lson,x);//不想打括号--
  39. else /*rson?0:rson=new_Node(),*/ Insert(m+1,r,rson,x);
  40. PushUp(rt);
  41. }
  42. }
  43. void Delete(int rt,int x,int &son)//可以用Insert将其值变为0来删除 但是就不能重复利用了
  44. {
  45. if(now.l==now.r) son=0, del_Node(rt);//父亲的这个儿子也要删!
  46. else
  47. {
  48. int m=now.l+now.r>>1;
  49. if(id[x]<=m) Delete(lson,x,lson);
  50. else Delete(rson,x,rson);
  51. if(now.sum==W[x]) del_Node(rt), son=0;
  52. else PushUp(rt);
  53. }
  54. }
  55. void Modify(int rt,int p,int v)
  56. {
  57. if(now.l==now.r) now.maxn=now.sum=v;
  58. else
  59. {
  60. int m=now.l+now.r>>1;
  61. if(p<=m) Modify(lson,p,v);
  62. else Modify(rson,p,v);
  63. PushUp(rt);
  64. }
  65. }
  66. int Query_Max(int rt,int L,int R)
  67. {
  68. if(!rt) return 0;
  69. if(L<=now.l && now.r<=R) return now.maxn;
  70. int m=now.l+now.r>>1;
  71. if(L<=m)
  72. if(m<R) return std::max(Query_Max(lson,L,R),Query_Max(rson,L,R));
  73. else return Query_Max(lson,L,R);
  74. return Query_Max(rson,L,R);
  75. }
  76. int Query_Sum(int rt,int L,int R)
  77. {
  78. if(!rt) return 0;
  79. if(L<=now.l && now.r<=R) return now.sum;
  80. int m=now.l+now.r>>1;
  81. if(L<=m)
  82. if(m<R) return Query_Sum(lson,L,R)+Query_Sum(rson,L,R);
  83. else return Query_Sum(lson,L,R);
  84. return Query_Sum(rson,L,R);
  85. }
  86. }t;
  87. #undef now
  88. inline int read()
  89. {
  90. int now=0,f=1;register char c=gc();
  91. for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
  92. for(;isdigit(c);now=now*10+c-'0',c=gc());
  93. return now*f;
  94. }
  95. inline void AddEdge(int u,int v)
  96. {
  97. to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
  98. to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
  99. }
  100. void DFS1(int x)
  101. {
  102. sz[x]=1; int mx=0;
  103. for(int v,i=H[x]; i; i=nxt[i])
  104. if((v=to[i])!=fa[x])
  105. {
  106. fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
  107. if(mx<sz[v]) mx=sz[v], son[x]=v;
  108. }
  109. }
  110. void DFS2(int x,int tp)
  111. {
  112. id[x]=++cnt, top[x]=tp;
  113. if(son[x])
  114. {
  115. DFS2(son[x],tp);
  116. for(int i=H[x]; i; i=nxt[i])
  117. if(to[i]!=fa[x] && to[i]!=son[x])
  118. DFS2(to[i], to[i]);
  119. }
  120. }
  121. void Query_Chain_Sum(int x,int y)
  122. {
  123. long long res=0;int rt=root[rel[x]];
  124. while(top[x]!=top[y])
  125. {
  126. if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
  127. res += t.Query_Sum(rt,id[top[x]],id[x]);
  128. x=fa[top[x]];
  129. }
  130. if(dep[x]>dep[y]) std::swap(x,y);
  131. res += t.Query_Sum(rt,id[x],id[y]);
  132. printf("%lld\n",res);
  133. }
  134. void Query_Chain_Max(int x,int y)
  135. {
  136. int res=0, rt=root[rel[x]];
  137. while(top[x]!=top[y])
  138. {
  139. if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
  140. res = std::max(res, t.Query_Max(rt,id[top[x]],id[x]));
  141. x=fa[top[x]];
  142. }
  143. if(dep[x]>dep[y]) std::swap(x,y);
  144. res = std::max(res, t.Query_Max(rt,id[x],id[y]));
  145. printf("%d\n",res);
  146. }
  147. int main()
  148. {
  149. #ifndef ONLINE_JUDGE
  150. freopen("3531.in","r",stdin);
  151. freopen("my.out","w",stdout);
  152. #endif
  153. n=read(),q=read();
  154. for(int i=1; i<MAXN; ++i) pool[i]=i;
  155. for(int i=1; i<=n; ++i) W[i]=read(), rel[i]=read();
  156. for(int u,v,i=1; i<n; ++i) u=read(),v=read(),AddEdge(u,v);
  157. DFS1(1), DFS2(1,1);
  158. for(int i=1; i<=n; ++i) t.Insert(1,n,root[rel[i]],i);
  159. char opt[5]; int x,y;
  160. while(q--)
  161. {
  162. scanf("%s",opt), x=read(), y=read();
  163. switch(opt[1])
  164. {
  165. case 'C': t.Delete(root[rel[x]],x,root[rel[x]]), rel[x]=y, t.Insert(1,n,root[y],x);
  166. break;
  167. case 'W': t.Modify(root[rel[x]],id[x],y), W[x]=y;//!
  168. break;
  169. case 'S': Query_Chain_Sum(x,y);
  170. break;
  171. case 'M': Query_Chain_Max(x,y);
  172. break;
  173. }
  174. }
  175. return 0;
  176. }

优化(短多了):

  1. //不知道为什么只需nlogn个节点 不需要回收
  2. //+各种函数简化
  3. #include<cstdio>
  4. #include<cctype>
  5. #include<algorithm>
  6. #define gc() getchar()
  7. #define now node[rt]
  8. #define lson node[rt].ls
  9. #define rson node[rt].rs
  10. const int N=1e5+5,MAXN=N*19;
  11. int n,q,cnt,H[N],Enum,to[N<<1],nxt[N<<1],fa[N],dep[N],id[N],son[N],sz[N],top[N];
  12. int idx,pos[N],W[N],rel[N],root[N],pool[MAXN];
  13. struct Seg_Tree
  14. {
  15. struct Node
  16. {
  17. int sum,maxn,ls,rs;
  18. inline void Init() {sum=maxn=ls=rs=0;}
  19. }node[MAXN];
  20. inline int new_Node() {return ++idx;}
  21. // inline int new_Node() {return pool[++idx];}
  22. // inline void del_Node(int rt) {now.Init(), pool[idx--]=rt;}
  23. inline void PushUp(int rt)
  24. {
  25. now.sum = node[lson].sum + node[rson].sum,
  26. now.maxn= std::max(node[lson].maxn, node[rson].maxn);
  27. }
  28. void Update(int l,int r,int &rt,int p,int v)
  29. {
  30. if(!rt) rt=new_Node();
  31. if(l==r) now.sum=now.maxn=v;
  32. else
  33. {
  34. int m=l+r>>1;
  35. if(p<=m) Update(l,m,lson,p,v);
  36. else Update(m+1,r,rson,p,v);
  37. PushUp(rt);
  38. }
  39. }
  40. int Query(int l,int r,int rt,int L,int R,bool opt)
  41. {
  42. if(!rt) return 0;
  43. if(L<=l && r<=R) return opt?now.sum:now.maxn;
  44. int m=l+r>>1;
  45. if(L<=m)
  46. if(m<R) return opt?Query(l,m,lson,L,R,opt)+Query(m+1,r,rson,L,R,opt)
  47. :std::max(Query(l,m,lson,L,R,opt),Query(m+1,r,rson,L,R,opt));
  48. else return Query(l,m,lson,L,R,opt);
  49. return Query(m+1,r,rson,L,R,opt);
  50. }
  51. }t;
  52. #undef now
  53. inline int read()
  54. {
  55. int now=0,f=1;register char c=gc();
  56. for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
  57. for(;isdigit(c);now=now*10+c-'0',c=gc());
  58. return now*f;
  59. }
  60. inline void AddEdge(int u,int v)
  61. {
  62. to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
  63. to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
  64. }
  65. void DFS1(int x)
  66. {
  67. sz[x]=1; int mx=-1;
  68. for(int v,i=H[x]; i; i=nxt[i])
  69. if((v=to[i])!=fa[x])
  70. {
  71. fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
  72. if(mx<sz[v]) mx=sz[v], son[x]=v;
  73. }
  74. }
  75. void DFS2(int x,int tp)
  76. {
  77. id[x]=++cnt, top[x]=tp;
  78. if(son[x])
  79. {
  80. DFS2(son[x],tp);
  81. for(int i=H[x]; i; i=nxt[i])
  82. if(to[i]!=fa[x] && to[i]!=son[x])
  83. DFS2(to[i], to[i]);
  84. }
  85. }
  86. void Query_Chain(int x,int y,bool opt)
  87. {
  88. int res=0;int rt=root[rel[x]];
  89. while(top[x]!=top[y])
  90. {
  91. if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
  92. if(opt) res += t.Query(1,n,rt,id[top[x]],id[x],1);
  93. else res = std::max(res, t.Query(1,n,rt,id[top[x]],id[x],0));
  94. x=fa[top[x]];
  95. }
  96. if(id[x]>id[y]) std::swap(x,y);
  97. if(opt) res += t.Query(1,n,rt,id[x],id[y],1);
  98. else res = std::max(res, t.Query(1,n,rt,id[x],id[y],0));
  99. printf("%d\n",res);
  100. }
  101. int main()
  102. {
  103. #ifndef ONLINE_JUDGE
  104. freopen("35312.in","r",stdin);
  105. freopen("my.out","w",stdout);
  106. #endif
  107. n=read(),q=read();
  108. for(int i=1; i<MAXN; ++i) pool[i]=i;
  109. for(int i=1; i<=n; ++i) W[i]=read(), rel[i]=read();
  110. for(int u,v,i=1; i<n; ++i) u=read(),v=read(),AddEdge(u,v);
  111. DFS1(1), DFS2(1,1);
  112. for(int i=1; i<=n; ++i) t.Update(1,n,root[rel[i]],id[i],W[i]);
  113. char opt[5]; int x,y;
  114. while(q--)
  115. {
  116. scanf("%s",opt), x=read(), y=read();
  117. switch(opt[1])
  118. {
  119. case 'C': t.Update(1,n,root[rel[x]],id[x],0), rel[x]=y, t.Update(1,n,root[y],id[x],W[x]);
  120. break;
  121. case 'W': t.Update(1,n,root[rel[x]],id[x],y),W[x]=y/*!*/; break;
  122. case 'S': Query_Chain(x,y,1); break;
  123. case 'M': Query_Chain(x,y,0); break;
  124. }
  125. }
  126. return 0;
  127. }

BZOJ.3531.旅行(树链剖分 动态开点)的更多相关文章

  1. BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树

    题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...

  2. 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)

    题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...

  3. 【BZOJ3531】[Sdoi2014]旅行 树链剖分+动态开点线段树

    [BZOJ3531][Sdoi2014]旅行 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天 ...

  4. 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

    题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...

  5. [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...

  6. 2018.07.24 bzoj3531: [Sdoi2014]旅行(树链剖分+动态开点)

    传送门 树链剖分. 如何维护? 如果颜色少直接每种颜色一颗线段树走人. 但这题颜色数量不大于1e5" role="presentation" style="po ...

  7. BZOJ 2157 旅行(树链剖分码农题)

    写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...

  8. bzoj3531: [Sdoi2014]旅行 (树链剖分 && 动态开点线段树)

    感觉动态开点线段树空间复杂度好优秀呀 树剖裸题 把每个宗教都开一颗线段树就可以了 但是我一直TLE 然后调了一个小时 为什么呢 因为我 #define max(x, y) (x > y ? x ...

  9. BZOJ 3531(树链剖分+线段树)

    Problem 旅行 (BZOJ 3531) 题目大意 给定一颗树,树上的每个点有两个权值(x,y). 要求维护4种操作: 操作1:更改某个点的权值x. 操作2:更改某个点的权值y. 操作3:求a-- ...

随机推荐

  1. 【vim】缩写 :ab [缩写] [要替换的文字]

    一个很可能是最令人印象深刻的窍门是你可以在 Vim 中定义缩写,它可以实时地把你输入的东西替换为另外的东西.语法格式如下: :ab [缩写] [要替换的文字] 一个通用的例子是: :ab asap a ...

  2. ARMV8 datasheet学习笔记3:AArch64应用级体系结构之Memory Type and Attributes

    1.前言 2. Memory类型和属性 memory分为normal memory和device memory,两种类型的Memory有各自的属性,除了下面介绍的几种属性外,还有其他一些杂项属性 2. ...

  3. 百度地图的Icon

    在百度地图的类说明中,查看对Icon的构建: 定制IconOptions 看下面的差别 发现在IconOptions没有imageSize属性 而在实际测试中,代码如下 <script type ...

  4. RestTemplate的使用

    1.postForObject :传入一个业务对象,返回是一个String 调用方: BaseUser baseUser=new BaseUser(); baseUser.setUserid(user ...

  5. python读取两个csv文件数据,进行查找匹配出现次数

    现有需求 表1 表2 需要拿表1中的编码去表2中的门票编码列匹配,统计出现的次数,由于表2编码列是区域间,而且列不是固定的,代码如下 #encoding:utf-8 ##导入两个CSV进行比对 imp ...

  6. python 全栈开发,Day64(视图,触发器,函数,存储过程,事务)

    昨日内容回顾 pymysql:属于python的一个模块 pip3 install pymysql conn = pymysql.connect(...,charset = 'uft8') 创建游标 ...

  7. 步步为营-71-asp.net的简单练习(图片处理)

    1 原有图片添加水印 1.1 封装一个类,用于获取文件路径 using System; using System.Collections.Generic; using System.IO; using ...

  8. JQuery编写自己的插件(七)

    一:jQuery插件的编写基础1.插件的种类编写插件的目的是给一系列已经方法或函数做一个封装,以便在其他地方重复使用,方便后期维护和提高开发效率.常见的种类有以下三种:封装对象方法的插件

  9. hdu 1728 迷宫 给定最大转弯次数 (BFS)

    给出起点 终点 以及转弯次数 在<=转弯次数的条件 能否走到终点 Sample Input25 5...** // .可走 *不可走*.**...........*....1 1 1 1 3 / ...

  10. zjoi2017 仙人掌

    题解: 好难的dp啊...看题解看了好久才看懂 http://blog.csdn.net/akak__ii/article/details/65935711 如果一开始的图就不是仙人掌,答案显然为0, ...