[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]之间。

题解:

树剖套路题。

线段树维护三个参数l,r,s,分别表示左边的颜色,右边的颜色以及这段区间中颜色的总数。

合并的时候就看一下左子树的l和右子树的r是否想等,相等就-1。

纯粹当板子题打的,代码应该还算比较好看

  1 //Never forget why you start
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<cmath>
  7 #include<algorithm>
  8 #define ll(x) (x<<1)
  9 #define rr(x) (x<<1|1)
 10 using namespace std;
 11 int n,m;
 12 int head[100005],size,a[100005];
 13 struct node{
 14   int next,to;
 15 }edge[200005];
 16 void putin(int from,int to){
 17   size++;
 18   edge[size].next=head[from];
 19   edge[size].to=to;
 20   head[from]=size;
 21 }
 22 int end[100005],fa[100005],depth[100005],top[100005],cnt[100005],son[100005],pos[100005],ppos[100005],dfscnt;
 23 void dfs1(int r,int father){
 24   int i;
 25   fa[r]=father;
 26   for(i=head[r];i!=-1;i=edge[i].next){
 27     int y=edge[i].to;
 28     if(y!=father){
 29       depth[y]=depth[r]+1;
 30       dfs1(y,r);
 31       cnt[r]+=cnt[y];
 32       if(son[r]==-1||cnt[y]>cnt[son[r]])son[r]=y;
 33     }
 34   }
 35   cnt[r]++;
 36 }
 37 void dfs2(int r,int tmp){
 38   int i;
 39   top[r]=tmp;
 40   pos[r]=++dfscnt;
 41   ppos[dfscnt]=r;
 42   if(son[r]!=-1)dfs2(son[r],tmp);
 43   for(i=head[r];i!=-1;i=edge[i].next){
 44     int y=edge[i].to;
 45     if(y!=fa[r]&&y!=son[r])
 46       dfs2(y,y);
 47   }
 48   end[r]=dfscnt;
 49 }
 50 struct segment{
 51   int l,r,sum,lazy;
 52   friend segment operator + (const segment a,const segment b){
 53     segment ans;
 54     if(a.sum==0)return b;
 55     if(b.sum==0)return a;
 56     ans.l=a.l;ans.r=b.r;
 57     ans.sum=a.sum+b.sum-(a.r==b.l);
 58     return ans;
 59   }
 60 }sgm[500005],zero;
 61 void push_up(int root){
 62   sgm[root].l=sgm[ll(root)].l;
 63   sgm[root].r=sgm[rr(root)].r;
 64   sgm[root].sum=sgm[ll(root)].sum+sgm[rr(root)].sum-(sgm[ll(root)].r==sgm[rr(root)].l);
 65   return;
 66 }
 67 void build(int root,int left,int right){
 68   if(left==right){
 69     sgm[root].sum=1;
 70     sgm[root].l=a[ppos[left]];
 71     sgm[root].r=a[ppos[left]];
 72     return;
 73   }
 74   if(left>right)return;
 75   int mid=(left+right)>>1;
 76   build(ll(root),left,mid);
 77   build(rr(root),mid+1,right);
 78   push_up(root);
 79 }
 80 void push_down(int root,int left,int right){
 81   if(!sgm[root].lazy)return;
 82   sgm[ll(root)].lazy=sgm[rr(root)].lazy=sgm[root].lazy;
 83   sgm[ll(root)].sum=sgm[rr(root)].sum=1;
 84   sgm[ll(root)].l=sgm[ll(root)].r=sgm[root].lazy;
 85   sgm[rr(root)].l=sgm[rr(root)].r=sgm[root].lazy;
 86   sgm[root].lazy=0;
 87   return;
 88 }
 89 void insert(int root,int left,int right,int l,int r,int v){
 90   if(l<=left&&right<=r){
 91     sgm[root].lazy=v;
 92     sgm[root].l=sgm[root].r=v;
 93     sgm[root].sum=1;
 94     return;
 95   }
 96   if(l>right||r<left)return;
 97   push_down(root,left,right);
 98   int mid=(left+right)>>1;
 99   if(l<=mid)insert(ll(root),left,mid,l,r,v);
100   if(mid<r)insert(rr(root),mid+1,right,l,r,v);
101   push_up(root);
102 }
103 segment query(int root,int left,int right,int l,int r){
104   if(l<=left&&right<=r)
105     return sgm[root];
106   if(l>right||r<left)return zero;
107   push_down(root,left,right);
108   int mid=(left+right)>>1;
109   segment ansl=zero,ansr=zero;
110   if(l<=mid)ansl=query(ll(root),left,mid,l,r);
111   if(mid<r)ansr=query(rr(root),mid+1,right,l,r);
112   return ansl+ansr;
113 }
114 int query_color(int root,int left,int right,int x){
115   if(left==right)
116     return sgm[root].l;
117   push_down(root,left,right);
118   int mid=(left+right)>>1;
119   if(x<=mid)return query_color(ll(root),left,mid,x);
120   else return query_color(rr(root),mid+1,right,x);
121 }
122 void chain_add(int x,int y,int v){
123   int f1=top[x],f2=top[y];
124   while(f1!=f2){
125     if(depth[f1]<depth[f2])swap(x,y),swap(f1,f2);
126     insert(1,1,n,pos[f1],pos[x],v);
127     x=fa[f1];f1=top[x];
128   }
129   if(depth[x]>depth[y])swap(x,y);
130   insert(1,1,n,pos[x],pos[y],v);
131 }
132 int chain_query(int x,int y){
133   int f1=top[x],f2=top[y],ans=0;
134   while(f1!=f2){
135     if(depth[f1]<depth[f2])swap(x,y),swap(f1,f2);
136     ans+=query(1,1,n,pos[f1],pos[x]).sum;
137     int a=query_color(1,1,n,pos[f1]);
138     int b=query_color(1,1,n,pos[fa[f1]]);
139     if(a==b)ans--;
140     x=fa[f1];f1=top[x];
141   }
142   if(depth[x]>depth[y])swap(x,y);
143   ans+=query(1,1,n,pos[x],pos[y]).sum;
144   return ans;
145 }
146 void clean(){
147   memset(head,-1,sizeof(head));
148   memset(son,-1,sizeof(son));
149   size=0;
150 }
151 int main(){
152   int i,j;
153   clean();
154   scanf("%d%d",&n,&m);
155   for(i=1;i<=n;i++)
156     scanf("%d",&a[i]);
157   for(i=1;i<n;i++){
158     int u,v;
159     scanf("%d%d",&u,&v);
160     putin(u,v);
161     putin(v,u);
162   }
163   depth[1]=1;
164   dfs1(1,0);
165   dfs2(1,0);
166   build(1,1,n);
167   for(i=1;i<=m;i++){
168     char s[2];int a,b,c;
169     scanf("%s%d%d",s,&a,&b);
170     if(s[0]=='C'){
171       scanf("%d",&c);
172       chain_add(a,b,c);
173     }
174     else{
175       printf("%d
",chain_query(a,b));
176     }
177   }
178   return 0;
179 }
原文地址:https://www.cnblogs.com/huangdalaofighting/p/8256875.html