题目大意:

给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作:

1、将u到v路径上所有边颜色翻转(黑->白,白->黑)

2、将只有一个点在u到v路径上的边颜色翻转

3、查询u到v路径上颜色为黑色的边数

如果只有1、3操作很好做,直接树链剖分+线段树,重点是2操作(废话)。

可以发现只有lca需要翻转和它父节点之间的边,因此将这条边暴力翻转。

现在剩下需要翻转的就是u到v路径上所有点与他们子节点之间的边。

我们将u到v的路径分成若干条重链,可以发现每条重链除了链低端的那个点,其他点要反转的是他们与他们所有轻儿子之间的边(这里注意特判lca少翻转了一条轻边)。

这么多边显然不能都翻转,那么我们再开一棵线段树,将重链上的点打标记,代表这些点与他们所有轻儿子之间的边需要翻转。

至于重链低端那个点还要暴力翻转它与重儿子间的边。

但现在只处理了每条重链,没有考虑两条链之间连接的那条边?

假设y链接在x链下面,那么x链低端那个点需要翻转的是除了一个轻边之外的其他轻边和一条重边,那么只需要将重边和不需要翻转的轻边翻转之后再打标记就好了。

将边下传到点,开两棵线段树,一棵维护边的颜色,另一棵维护给轻儿子翻转的标记(这棵线段树建议标记永久化),每次修改时注意链与链之间轻边的翻转即可。

  1. #include<set>
  2. #include<map>
  3. #include<stack>
  4. #include<queue>
  5. #include<cmath>
  6. #include<cstdio>
  7. #include<vector>
  8. #include<bitset>
  9. #include<cstring>
  10. #include<iostream>
  11. #include<algorithm>
  12. #define ll long long
  13. using namespace std;
  14. int T;
  15. int n,m;
  16. int x,y;
  17. int tot;
  18. int opt;
  19. int num;
  20. int a[800010];
  21. int b[800010];
  22. int d[100010];
  23. int f[100010];
  24. int s[100010];
  25. int to[200010];
  26. int sum[800010];
  27. int son[100010];
  28. int top[100010];
  29. int size[100010];
  30. int head[100010];
  31. int next[200010];
  32. void add(int x,int y)
  33. {
  34. tot++;
  35. next[tot]=head[x];
  36. head[x]=tot;
  37. to[tot]=y;
  38. }
  39. void dfs(int x)
  40. {
  41. d[x]=d[f[x]]+1;
  42. size[x]=1;
  43. for(int i=head[x];i;i=next[i])
  44. {
  45. if(to[i]!=f[x])
  46. {
  47. f[to[i]]=x;
  48. dfs(to[i]);
  49. size[x]+=size[to[i]];
  50. if(size[to[i]]>size[son[x]])
  51. {
  52. son[x]=to[i];
  53. }
  54. }
  55. }
  56. }
  57. void dfs2(int x,int tp)
  58. {
  59. s[x]=++num;
  60. top[x]=tp;
  61. if(son[x])
  62. {
  63. dfs2(son[x],tp);
  64. }
  65. for(int i=head[x];i;i=next[i])
  66. {
  67. if(to[i]!=f[x]&&to[i]!=son[x])
  68. {
  69. dfs2(to[i],to[i]);
  70. }
  71. }
  72. }
  73. void updata(int rt,int l,int r,int L,int R)
  74. {
  75. if(L<=l&&r<=R)
  76. {
  77. b[rt]^=1;
  78. return ;
  79. }
  80. int mid=(l+r)>>1;
  81. if(L<=mid)
  82. {
  83. updata(rt<<1,l,mid,L,R);
  84. }
  85. if(R>mid)
  86. {
  87. updata(rt<<1|1,mid+1,r,L,R);
  88. }
  89. }
  90. int downdata(int rt,int l,int r,int k)
  91. {
  92. if(l==r)
  93. {
  94. return b[rt];
  95. }
  96. int res=b[rt];
  97. int mid=(l+r)>>1;
  98. if(k<=mid)
  99. {
  100. return res^downdata(rt<<1,l,mid,k);
  101. }
  102. else
  103. {
  104. return res^downdata(rt<<1|1,mid+1,r,k);
  105. }
  106. }
  107. void pushup(int rt)
  108. {
  109. sum[rt]=sum[rt<<1]+sum[rt<<1|1];
  110. }
  111. void pushdown(int rt,int l,int r)
  112. {
  113. if(a[rt])
  114. {
  115. int mid=(l+r)>>1;
  116. a[rt<<1]^=1;
  117. a[rt<<1|1]^=1;
  118. sum[rt<<1]=(mid-l+1)-sum[rt<<1];
  119. sum[rt<<1|1]=(r-mid)-sum[rt<<1|1];
  120. a[rt]=0;
  121. }
  122. }
  123. void change1(int rt,int l,int r,int k)
  124. {
  125. if(l==r)
  126. {
  127. sum[rt]^=1;
  128. return ;
  129. }
  130. pushdown(rt,l,r);
  131. int mid=(l+r)>>1;
  132. if(k<=mid)
  133. {
  134. change1(rt<<1,l,mid,k);
  135. }
  136. else
  137. {
  138. change1(rt<<1|1,mid+1,r,k);
  139. }
  140. pushup(rt);
  141. }
  142. void change2(int rt,int l,int r,int L,int R)
  143. {
  144. if(L<=l&&r<=R)
  145. {
  146. a[rt]^=1;
  147. sum[rt]=(r-l+1)-sum[rt];
  148. return ;
  149. }
  150. pushdown(rt,l,r);
  151. int mid=(l+r)>>1;
  152. if(L<=mid)
  153. {
  154. change2(rt<<1,l,mid,L,R);
  155. }
  156. if(R>mid)
  157. {
  158. change2(rt<<1|1,mid+1,r,L,R);
  159. }
  160. pushup(rt);
  161. }
  162. int query1(int rt,int l,int r,int k)
  163. {
  164. if(l==r)
  165. {
  166. return sum[rt];
  167. }
  168. pushdown(rt,l,r);
  169. int mid=(l+r)>>1;
  170. if(k<=mid)
  171. {
  172. return query1(rt<<1,l,mid,k);
  173. }
  174. else
  175. {
  176. return query1(rt<<1|1,mid+1,r,k);
  177. }
  178. }
  179. int query2(int rt,int l,int r,int L,int R)
  180. {
  181. if(L<=l&&r<=R)
  182. {
  183. return sum[rt];
  184. }
  185. pushdown(rt,l,r);
  186. int mid=(l+r)>>1;
  187. int res=0;
  188. if(L<=mid)
  189. {
  190. res+=query2(rt<<1,l,mid,L,R);
  191. }
  192. if(R>mid)
  193. {
  194. res+=query2(rt<<1|1,mid+1,r,L,R);
  195. }
  196. return res;
  197. }
  198. void rotate1(int x,int y)
  199. {
  200. while(top[x]!=top[y])
  201. {
  202. if(d[top[x]]<d[top[y]])
  203. {
  204. swap(x,y);
  205. }
  206. change2(1,1,n,s[top[x]],s[x]);
  207. x=f[top[x]];
  208. }
  209. if(d[x]>d[y])
  210. {
  211. swap(x,y);
  212. }
  213. if(x==y)
  214. {
  215. return ;
  216. }
  217. change2(1,1,n,s[x]+1,s[y]);
  218. }
  219. void rotate2(int x,int y)
  220. {
  221. if(son[x])
  222. {
  223. change1(1,1,n,s[x]+1);
  224. }
  225. if(son[y])
  226. {
  227. change1(1,1,n,s[y]+1);
  228. }
  229. while(top[x]!=top[y])
  230. {
  231. if(d[top[x]]<d[top[y]])
  232. {
  233. swap(x,y);
  234. }
  235. updata(1,1,n,s[top[x]],s[x]);
  236. change1(1,1,n,s[top[x]]);
  237. x=f[top[x]];
  238. change1(1,1,n,s[x]+1);
  239. }
  240. if(d[x]>d[y])
  241. {
  242. swap(x,y);
  243. }
  244. change1(1,1,n,s[x]);
  245. change1(1,1,n,s[x]+1);
  246. updata(1,1,n,s[x],s[y]);
  247. }
  248. int ask(int x,int y)
  249. {
  250. int res=0;
  251. int ans;
  252. while(top[x]!=top[y])
  253. {
  254. if(d[top[x]]<d[top[y]])
  255. {
  256. swap(x,y);
  257. }
  258. if(top[x]!=x)
  259. {
  260. res+=query2(1,1,n,s[top[x]]+1,s[x]);
  261. }
  262. ans=query1(1,1,n,s[top[x]]);
  263. x=f[top[x]];
  264. res+=(ans^downdata(1,1,n,s[x]));
  265. }
  266. if(d[x]>d[y])
  267. {
  268. swap(x,y);
  269. }
  270. if(x==y)
  271. {
  272. return res;
  273. }
  274. res+=query2(1,1,n,s[x]+1,s[y]);
  275. return res;
  276. }
  277. int main()
  278. {
  279. scanf("%d",&T);
  280. while(T--)
  281. {
  282. num=0;
  283. tot=0;
  284. memset(a,0,sizeof(a));
  285. memset(b,0,sizeof(b));
  286. memset(f,0,sizeof(f));
  287. memset(d,0,sizeof(d));
  288. memset(s,0,sizeof(s));
  289. memset(to,0,sizeof(to));
  290. memset(son,0,sizeof(son));
  291. memset(top,0,sizeof(top));
  292. memset(sum,0,sizeof(sum));
  293. memset(size,0,sizeof(size));
  294. memset(head,0,sizeof(head));
  295. memset(next,0,sizeof(next));
  296. scanf("%d",&n);
  297. for(int i=1;i<n;i++)
  298. {
  299. scanf("%d%d",&x,&y);
  300. add(x,y);
  301. add(y,x);
  302. }
  303. dfs(1);
  304. dfs2(1,1);
  305. scanf("%d",&m);
  306. for(int i=1;i<=m;i++)
  307. {
  308. scanf("%d%d%d",&opt,&x,&y);
  309. if(opt==1)
  310. {
  311. rotate1(x,y);
  312. }
  313. else if(opt==2)
  314. {
  315. rotate2(x,y);
  316. }
  317. else
  318. {
  319. printf("%d\n",ask(x,y));
  320. }
  321. }
  322. }
  323. }

BZOJ3862Little Devil I——树链剖分+线段树的更多相关文章

  1. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  2. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  3. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  4. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  5. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  6. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  7. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  8. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  9. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

随机推荐

  1. eclipse打断点的调试

    对于程序员来说,最重要的技能之一其实是在发现问题的时候,定位问题,然后才能解决问题. 发现问题的能力十分的重要.而debug的水平就是基础. 打断点之后,操作相应的步骤,然后eclipse会跳转到相应 ...

  2. sql字符串累加

    函数 stuff(param1, startIndex, length, param2) 函数说明将param1中自startIndex(SQL中都是从1开始,而非0)起,删除length个字符,然后 ...

  3. [C#]使用Windows Form开发的百度网盘搜索工具

    BaiduDiskSearcher 用C#编写的百度网盘搜索工具(.NET4.0 & Visual Studio 2017) 功能 1.搜索任意名称的百度网盘共享文件 2.可以左键双击打开网盘 ...

  4. Error【0006】:could not create or update nagios.configtest

    1. 错误背景 在本系列博客<Nagios监控系统部署(源码).md>中(笔记内链:Nagios监控系统部署(源码).md,博客园地址:https://www.cnblogs.com/li ...

  5. 【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--控制器和处理函数的注册篇(4/8)【controller+action】

    文章目录 前情概要 前边的文章把一些基本的前置任务都完成了.接下就是比较重要的处理函数action是如何自动发现和注册的拉,也就是入口函数RouteHandler(也是我们的第一个express中间件 ...

  6. zookeeper Error contacting service 解决

    连接kafka集群,有一个kafka机器连接失败 到该kafka机器上查询kafka进程,发现没有, 再查看zookeeper状态,提示 Error contacting service. It is ...

  7. Python中 and or 运算顺序详解 --- 短路逻辑

    核心思想 表达式从左至右运算,若 or 的左侧逻辑值为 True ,则短路 or 后所有的表达式(不管是 and 还是 or),直接输出 or 左侧表达式 . 表达式从左至右运算,若 and 的左侧逻 ...

  8. windows平台下编辑的内容传到linux平台出现中文乱码的解决办法

    现象说明:在windows下编辑的内容,上传到linux平台下出现中文乱码.如下: 在windows平台编写haha.txt文件,内容如下: 上传到linux平台,出现中文乱码,如下: 基本上面出现的 ...

  9. C++ string简单的使用技巧

    截取substr //string的操作 #include<iostream> using namespace std; int main() { string a,b; a=" ...

  10. 第三次作业(1) Visual Studio程序安装过程和练习过程

    Visual Studio程序安装过程和练习过程 第一步 首先要在网上找一个VS2013的安装包,之后我安装在D盘上,C盘上也需要有5.2G空间,勾选相应的选项,才能继续安装. 安装的过程很漫长,接近 ...