题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243

题意:

  给定一棵有n个节点的无根树和m个操作,操作有2类:

  1、将节点a到节点b路径上所有点都染成颜色c;

  2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"、"222"和"1"。

  请你写一个程序依次完成这m个操作。

题解:

  树剖。

  线段树上维护区间颜色段,每个节点:

    dat[]:当前区间的颜色段数量

    st[]:修改标记

    lc[] and rc[]:当前区间的最左端和最右端颜色

    lson[] and rson[]:左右儿子编号

  线段树部分见NOI 2007 项链工厂。

  树剖query中,每次a = par[tp[a]]往上跳之前,先判断getcol(dfsx[tp[a]]) == getcol(dfsx[par[tp[a]]])

  如果相等,上下两端合并,sum--。

AC Code:

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <vector>
  5. #define MAX_N 1000005
  6.  
  7. using namespace std;
  8.  
  9. int n,m;
  10. int tot=;
  11. int cnt=;
  12. int c[MAX_N];
  13. int dat[MAX_N];
  14. int st[MAX_N];
  15. int lc[MAX_N];
  16. int rc[MAX_N];
  17. int lson[MAX_N];
  18. int rson[MAX_N];
  19. int par[MAX_N];
  20. int dep[MAX_N];
  21. int siz[MAX_N];
  22. int tp[MAX_N];
  23. int son[MAX_N];
  24. int dfsx[MAX_N];
  25. int idx[MAX_N];
  26. vector<int> edge[MAX_N];
  27.  
  28. void read()
  29. {
  30. scanf("%d%d",&n,&m);
  31. for(int i=;i<=n;i++)
  32. {
  33. scanf("%d",&c[i]);
  34. }
  35. int a,b;
  36. for(int i=;i<n;i++)
  37. {
  38. scanf("%d%d",&a,&b);
  39. edge[a].push_back(b);
  40. edge[b].push_back(a);
  41. }
  42. }
  43.  
  44. void push_down(int now)
  45. {
  46. if(st[now]!=-)
  47. {
  48. dat[lson[now]]=dat[rson[now]]=;
  49. st[lson[now]]=st[rson[now]]=st[now];
  50. lc[lson[now]]=rc[lson[now]]=lc[rson[now]]=rc[rson[now]]=st[now];
  51. st[now]=-;
  52. }
  53. }
  54.  
  55. void push_up(int now)
  56. {
  57. dat[now]=;
  58. lc[now]=lc[lson[now]];
  59. rc[now]=rc[rson[now]];
  60. if(lson[now]) dat[now]+=dat[lson[now]];
  61. if(rson[now]) dat[now]+=dat[rson[now]];
  62. if(lson[now] && rson[now] && rc[lson[now]]==lc[rson[now]]) dat[now]--;
  63. }
  64.  
  65. int build(int l,int r)
  66. {
  67. int rt=++tot;
  68. dat[rt]=;
  69. st[rt]=-;
  70. lc[rt]=c[idx[l]];
  71. rc[rt]=c[idx[r]];
  72. lson[rt]=rson[rt]=;
  73. if(l<r)
  74. {
  75. int mid=(l+r)>>;
  76. lson[rt]=build(l,mid);
  77. rson[rt]=build(mid+,r);
  78. push_up(rt);
  79. }
  80. return rt;
  81. }
  82.  
  83. void update(int a,int b,int k,int l,int r,int x)
  84. {
  85. if(a<=l && r<=b)
  86. {
  87. dat[k]=;
  88. st[k]=lc[k]=rc[k]=x;
  89. return;
  90. }
  91. if(r<a || b<l) return;
  92. push_down(k);
  93. int mid=(l+r)>>;
  94. update(a,b,lson[k],l,mid,x);
  95. update(a,b,rson[k],mid+,r,x);
  96. push_up(k);
  97. }
  98.  
  99. int query(int a,int b,int k,int l,int r)
  100. {
  101. if(a<=l && r<=b) return dat[k];
  102. if(r<a || b<l) return ;
  103. push_down(k);
  104. int mid=(l+r)>>;
  105. int ans=;
  106. if(a<=mid) ans+=query(a,b,lson[k],l,mid);
  107. if(b>mid) ans+=query(a,b,rson[k],mid+,r);
  108. if(a<=mid && b>mid && rc[lson[k]]==lc[rson[k]]) ans--;
  109. return ans;
  110. }
  111.  
  112. int getcol(int p,int k,int l,int r)
  113. {
  114. if(l==r) return lc[k];
  115. push_down(k);
  116. int mid=(l+r)>>;
  117. if(p<=mid) return getcol(p,lson[k],l,mid);
  118. else return getcol(p,rson[k],mid+,r);
  119. }
  120.  
  121. void dfs1(int now,int p,int d)
  122. {
  123. par[now]=p;
  124. dep[now]=d;
  125. siz[now]=;
  126. for(int i=;i<edge[now].size();i++)
  127. {
  128. int temp=edge[now][i];
  129. if(temp!=p)
  130. {
  131. dfs1(temp,now,d+);
  132. siz[now]+=siz[temp];
  133. }
  134. }
  135. }
  136.  
  137. void dfs2(int now,int anc)
  138. {
  139. tp[now]=anc;
  140. son[now]=-;
  141. cnt++;
  142. idx[cnt]=now;
  143. dfsx[now]=cnt;
  144. for(int i=;i<edge[now].size();i++)
  145. {
  146. int temp=edge[now][i];
  147. if((son[now]==- || siz[temp]>siz[son[now]]) && temp!=par[now])
  148. {
  149. son[now]=temp;
  150. }
  151. }
  152. if(son[now]!=-) dfs2(son[now],anc);
  153. for(int i=;i<edge[now].size();i++)
  154. {
  155. int temp=edge[now][i];
  156. if(temp!=par[now] && temp!=son[now]) dfs2(temp,temp);
  157. }
  158. }
  159.  
  160. void update_chain(int a,int b,int x)
  161. {
  162. while(tp[a]!=tp[b])
  163. {
  164. if(dep[tp[a]]<dep[tp[b]]) swap(a,b);
  165. update(dfsx[tp[a]],dfsx[a],,,n,x);
  166. a=par[tp[a]];
  167. }
  168. if(dep[a]<dep[b]) swap(a,b);
  169. update(dfsx[b],dfsx[a],,,n,x);
  170. }
  171.  
  172. int query_chain(int a,int b)
  173. {
  174. int sum=;
  175. while(tp[a]!=tp[b])
  176. {
  177. if(dep[tp[a]]<dep[tp[b]]) swap(a,b);
  178. sum+=query(dfsx[tp[a]],dfsx[a],,,n);
  179. if(getcol(dfsx[tp[a]],,,n)==getcol(dfsx[par[tp[a]]],,,n)) sum--;
  180. a=par[tp[a]];
  181. }
  182. if(dep[a]<dep[b]) swap(a,b);
  183. sum+=query(dfsx[b],dfsx[a],,,n);
  184. return sum;
  185. }
  186.  
  187. void work()
  188. {
  189. dfs1(,-,);
  190. dfs2(,);
  191. build(,n);
  192. char s[];
  193. int a,b,c;
  194. while(m--)
  195. {
  196. scanf("%s",s);
  197. if(s[]=='Q')
  198. {
  199. scanf("%d%d",&a,&b);
  200. printf("%d\n",query_chain(a,b));
  201. }
  202. else
  203. {
  204. scanf("%d%d%d",&a,&b,&c);
  205. update_chain(a,b,c);
  206. }
  207. }
  208. }
  209.  
  210. int main()
  211. {
  212. read();
  213. work();
  214. }

BZOJ 2243 [SDOI2011]染色:树剖【维护路径上颜色段】的更多相关文章

  1. BZOJ 2243: [SDOI2011]染色 (树剖+线段树)

    树链剖分后两个区间合并的时候就判一下相交颜色是否相同来算颜色段数就行了. CODE #include <vector> #include <queue> #include &l ...

  2. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

  3. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

  4. BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  5. BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

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

  6. BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)

    [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6870  Solved: 2546[Submit][Status][Disc ...

  7. [bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]

    Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ ...

  8. BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分的点剖分+线段树.漏了一个小地方,调了一下午...... 还是要细心啊! 结 ...

  9. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

随机推荐

  1. HTML5 2D平台游戏开发#9蓄力技

    在很多动作游戏中,玩家操控的角色可以施放出比普通攻击更强力的蓄力技,一般操作为按住攻击键一段时间然后松开,具体效果像下面这张图: 要实现这个操作首先要记录下按键被按住的时间,初始是0: this.sa ...

  2. 一个方便的图片载入框架——ImageViewEx

    我的博客:http://mrfufufu.github.io/ 一.前言 近期在整理项目中的一些代码,以备即将开展的新项目中使用,刚刚整理到一个图片载入的 lib.用起来很的简单,和 picasso ...

  3. UIview层次管理

    将一个UIView显示在最前面只需要调用其父视图的 bringSubviewToFront()方法. 将一个UIView层推送到背后只需要调用其父视图的 sendSubviewToBack()方法.

  4. CentOS6.4下编译安装Apache2.4+PHP5.6

    安装Apache2.4: 首先从  http://httpd.apache.org/download.cgi#apache24下载apache源码包httpd-2.4.4.tar.gz从  http: ...

  5. 【文献阅读】Perceptual Generative Adversarial Networks for Small Object Detection –CVPR-2017

    Perceptual Generative Adversarial Networks for Small Object Detection 2017CVPR 新鲜出炉的paper,这是针对small ...

  6. 三种光照模型的shader实现

    1.Lambert模型,公式为I=Kd*Il(N*L): Shader "Custom/Lambert_A" { Properties { _Diffuse(,,,) } SubS ...

  7. PHP fsockopen模拟POST/GET方法

    原文链接:http://www.nowamagic.net/academy/detail/12220214 fsockopen 除了前面小节的模拟生成 HTTP 连接之外,还能实现很多功能,比如模拟  ...

  8. java.lang.IllegalStateException: ImageView no longer exists. You should not use this PhotoViewAttacher any more.

    java.lang.IllegalStateException: ImageView no longer exists. You should not use this PhotoViewAttach ...

  9. SDOI2012 Round1 day2 集合(set)解题报告

    //=====================以上为官方题解==============// 数据略水,暴力枚举50. 把边按照升序排一遍,在询问,水过. #include<cstdio> ...

  10. 【BZOJ3791】作业 DP

    [BZOJ3791]作业 Description 众所周知,白神是具有神奇的能力的.比如说,他对数学作业说一声“数”,数学作业就会出于畏惧而自己完成:对语文作业说一声“语”,语文作业就会出于畏惧而自己 ...