2243. [SDOI2011]染色【树链剖分】

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

Sample Input

6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5

Sample Output

3
1
2

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

一眼:链剖
两眼:链剖+两个区间相邻处特判
和学长说了一句:感觉不是很难写(flag)
然后我处理的时候是直接当区间修改时用for循环将线段树区间更新
……正确性当然可以保证啦……出乎意料的是并没有T飞……就T了一个点
去隔壁请教了学长被告知要维护线段树的两端颜色……
于是开始了漫长的调试……
其实这个题只要想到了维护两端的值就很好搞了啊……
哪怕像我想不到维护两端也有95可拿对不对【滑稽】

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #define MAX (150000+5)
  6 using namespace std;
  7 struct node
  8 {
  9     int down;//下传标记
 10     int sum;//该区间有几种颜色
 11     int l,r;//该区间左右端点的颜色
 12 } Segt[MAX*4];
 13 struct node1
 14 {
 15     int to;
 16     int next;
 17 } edge[MAX*2];
 18 int Father[MAX],Depth[MAX];
 19 int Sum[MAX],Son[MAX],Top[MAX];
 20 int TREE[MAX],T_NUM[MAX];
 21 int num_edge,head[MAX],n,cnt;
 22 int a[MAX];
 23 
 24 inline int get()//神TM快读,维护左右颜色前卡常用的但没卡过去
 25 {
 26     char c;
 27     int x=0,f=1;
 28     c=getchar();
 29     while (c<'0'||c>'9')
 30     {
 31         if (c=='-') f=-1;
 32         c=getchar();
 33     }
 34     while (c>='0'&&c<='9')
 35     {
 36         x=x*10+c-'0';
 37         c=getchar();
 38     }
 39     return x*f;
 40 }
 41 
 42 void add(int u,int v)
 43 {
 44     edge[++num_edge].to=v;
 45     edge[num_edge].next=head[u];
 46     head[u]=num_edge;
 47 }
 48 
 49 void Build(int node,int l,int r)
 50 {
 51     if (l==r)
 52     {
 53         Segt[node].sum=1;
 54         Segt[node].l=Segt[node].r=TREE[l];
 55     }
 56     else
 57     {
 58         int mid=(l+r)/2;
 59         Build(node*2,l,mid);
 60         Build(node*2+1,mid+1,r);//这里维护好麻烦啊……早知道写个pushup了
 61         Segt[node].l=Segt[node*2].l;
 62         Segt[node].r=Segt[node*2+1].r;
 63         Segt[node].sum=Segt[node*2].sum+Segt[node*2+1].sum-(Segt[node*2].r==Segt[node*2+1].l);
 64     }
 65 }
 66 
 67 void Pushdown(int node)
 68 {
 69     if (Segt[node].down!=0)
 70     {
 71         Segt[node*2].sum=1;//因为修改成了一个数所以肯定只有一种颜色
 72         Segt[node*2+1].sum=1;
 73 
 74         Segt[node*2].down=Segt[node].down;//down存下传的颜色编号
 75         Segt[node*2+1].down=Segt[node].down;
 76 
 77         Segt[node*2].l=Segt[node*2].r=Segt[node].down;
 78         Segt[node*2+1].l=Segt[node*2+1].r=Segt[node].down;
 79 
 80         Segt[node].down=0;
 81     }
 82 }
 83 
 84 int Query(int node,int l,int r,int l1,int r1)
 85 {
 86     if (r<l1 || l>r1)
 87         return 0;
 88     if (l1<=l && r<=r1)
 89         return Segt[node].sum;
 90     Pushdown(node);
 91     int mid=(l+r)/2;
 92     int x=Query(node*2,l,mid,l1,r1);
 93     int y=Query(node*2+1,mid+1,r,l1,r1);
 94     if (x!=0 && y!=0)
 95         return x+y-(Segt[node*2].r==Segt[node*2+1].l);
 96     return max(x,y);
 97 }
 98 
 99 void Update(int node,int l,int r,int l1,int r1,int k)//区间更新模板
100 {
101     if (r<l1 || l>r1)
102         return;
103     if (l1<=l && r<=r1)
104     {
105         Segt[node].down=k;
106         Segt[node].sum=1;
107         Segt[node].l=Segt[node].r=k;
108         return;
109     }
110     Pushdown(node);
111     int mid=(l+r)/2;
112     Update(node*2,l,mid,l1,r1,k);
113     Update(node*2+1,mid+1,r,l1,r1,k);//再一次后悔没写pushup
114     Segt[node].l=Segt[node*2].l;
115     Segt[node].r=Segt[node*2+1].r;
116     Segt[node].sum=Segt[node*2].sum+Segt[node*2+1].sum-(Segt[node*2].r==Segt[node*2+1].l);
117 }
118 
119 int Ask(int node,int l,int r,int x)//查询某个点的颜色
120 {
121     if (l==r)
122         return Segt[node].l;
123     else
124     {
125         Pushdown(node);
126         int mid=(l+r)/2;
127         if (x<=mid)    return Ask(node*2,l,mid,x);
128         else return Ask(node*2+1,mid+1,r,x);
129     }
130 }
131 
132 int Get(int x,int y)
133 {
134     int fx=Top[x],fy=Top[y];
135     int Ans=0;
136     while (fx!=fy)
137     {
138         if (Depth[fx]<Depth[fy])
139             swap(fx,fy),swap(x,y);
140         int re=Ask(1,1,n,T_NUM[fx]);
141         int fun=Ask(1,1,n,T_NUM[Father[fx]]);
142         Ans+=Query(1,1,n,T_NUM[fx],T_NUM[x])-(re==fun);
143         x=Father[fx],fx=Top[x];
144     }
145     if (Depth[x]<Depth[y])
146         swap(x,y);
147     return Ans+=Query(1,1,n,T_NUM[y],T_NUM[x]);
148 }
149 
150 void Change(int x,int y,int k)
151 {
152     int fx=Top[x],fy=Top[y];
153     while (fx!=fy)
154     {
155         if (Depth[fx]<Depth[fy])
156             swap(fx,fy),swap(x,y);
157         Update(1,1,n,T_NUM[fx],T_NUM[x],k);
158         x=Father[fx],fx=Top[x];
159     }
160     if (Depth[x]<Depth[y])
161         swap(x,y);
162     Update(1,1,n,T_NUM[y],T_NUM[x],k);
163 }
164 
165 void Dfs1(int x)
166 {
167     Depth[x]=Depth[Father[x]]+1;
168     Sum[x]=1;
169     for (int i=head[x]; i!=0; i=edge[i].next)
170         if (edge[i].to!=Father[x])
171         {
172             Father[edge[i].to]=x;
173             Dfs1(edge[i].to);
174             Sum[x]+=Sum[edge[i].to];
175             if (Son[x]==0 || Sum[Son[x]]<Sum[edge[i].to])
176                 Son[x]=edge[i].to;
177         }
178 }
179 
180 void Dfs2(int x,int pre)
181 {
182     TREE[++cnt]=a[x];
183     T_NUM[x]=cnt;
184     Top[x]=pre;
185     if (Son[x]!=0)
186         Dfs2(Son[x],pre);
187     for (int i=head[x]; i!=0; i=edge[i].next)
188         if (edge[i].to!=Son[x] && edge[i].to!=Father[x])
189             Dfs2(edge[i].to,edge[i].to);
190 }
191 
192 int main()
193 {
194     char ch;
195     int x,y,k,m,u,v;
196     n=get();
197     m=get();
198     for (int i=1; i<=n; ++i)
199         a[i]=get();
200     for (int i=1; i<=n-1; ++i)
201     {
202         u=get();
203         v=get();
204         add(u,v);
205         add(v,u);
206     }
207     Dfs1(1);
208     Father[1]=1;
209     Dfs2(1,1);
210     Build(1,1,n);
211     for (int i=1; i<=m; ++i)
212     {
213         ch=getchar();
214         while (ch!='C'&&ch!='Q') ch=getchar();
215         if (ch=='Q')
216             x=get(),y=get(),printf("%d
",Get(x,y));
217         else
218             x=get(),y=get(),k=get(),Change(x,y,k);
219     }
220 }
原文地址:https://www.cnblogs.com/refun/p/8678489.html