【bzoj2243】[SDOI2011]染色

题目描述

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

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

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

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

输入

第一行包含2个整数n和m,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面 行每行包含两个整数x和y,表示xy之间有一条无向边。

下面 行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

输出

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

样例输入

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

样例输出

3

1

2

提示

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


题解

裸的树链剖分+线段树。

区间修改非常恶心,很多细节。

多写写应该就能好了吧。。。

  1 #include <stdio.h>
  2 #include <algorithm>
  3 using namespace std;
  4 #define lson l , mid , x << 1
  5 #define rson mid + 1 , r , x << 1 | 1
  6 #define N 100005
  7 int fa[N] , deep[N] , si[N] , val[N] , bl[N] , pos[N] , tot;
  8 int head[N] , to[N << 1] , next[N << 1] , cnt;
  9 int sum[N << 3] , lc[N << 3] , rc[N << 3] , mark[N << 3] , n;
 10 char str[10];
 11 void add(int x , int y)
 12 {
 13     to[++cnt] = y;
 14     next[cnt] = head[x];
 15     head[x] = cnt;
 16 }
 17 void dfs1(int x)
 18 {
 19     int i , y;
 20     si[x] = 1;
 21     for(i = head[x] ; i ; i = next[i])
 22     {
 23         y = to[i];
 24         if(y != fa[x])
 25         {
 26             fa[y] = x;
 27             deep[y] = deep[x] + 1;
 28             dfs1(y);
 29             si[x] += si[y];
 30         }
 31     }
 32 }
 33 void dfs2(int x , int c)
 34 {
 35     int k = 0 , i , y;
 36     bl[x] = c;
 37     pos[x] = ++tot;
 38     for(i = head[x] ; i ; i = next[i])
 39     {
 40         y = to[i];
 41         if(fa[x] != y && si[y] > si[k])
 42             k = y;
 43     }
 44     if(k != 0)
 45     {
 46         dfs2(k , c);
 47         for(i = head[x] ; i ; i = next[i])
 48         {
 49             y = to[i];
 50             if(fa[x] != y && y != k)
 51                 dfs2(y , y);
 52         }
 53     }
 54 }
 55 void pushup(int x)
 56 {
 57     lc[x] = lc[x << 1];
 58     rc[x] = rc[x << 1 | 1];
 59     sum[x] = sum[x << 1] + sum[x << 1 | 1];
 60     if(rc[x << 1] == lc[x << 1 | 1])
 61         sum[x] -- ;
 62 }
 63 void pushdown(int x)
 64 {
 65     int tmp = mark[x];
 66     mark[x] = 0;
 67     if(tmp)
 68     {
 69         sum[x << 1] = sum[x << 1 | 1] = 1;
 70         lc[x << 1] = rc[x << 1] = lc[x << 1 | 1] = rc[x << 1 | 1] = tmp;
 71         mark[x << 1] = mark[x << 1 | 1] = tmp;
 72     }
 73 }
 74 void update(int b , int e , int v , int l , int r , int x)
 75 {
 76     pushdown(x);
 77     if(b <= l && r <= e)
 78     {
 79         sum[x] = 1;
 80         lc[x] = rc[x] = v;
 81         mark[x] = v;
 82         return;
 83     }
 84     int mid = (l + r) >> 1;
 85     if(b <= mid)
 86         update(b , e , v , lson);
 87     if(e > mid)
 88         update(b , e , v , rson);
 89     pushup(x);
 90 }
 91 void solveupdate(int x , int y , int v)
 92 {
 93     while(bl[x] != bl[y])
 94     {
 95         if(deep[bl[x]] < deep[bl[y]])
 96         {
 97             swap(x , y);
 98         }
 99         update(pos[bl[x]] , pos[x] , v , 1 , n , 1);
100         x = fa[bl[x]];
101     }
102     if(deep[x] > deep[y])
103         swap(x , y);
104     update(pos[x] , pos[y] , v , 1 , n , 1);
105 }
106 int query(int b , int e , int l , int r , int x)
107 {
108     pushdown(x);
109     if(b <= l && r <= e)
110     {
111         return sum[x];
112     }
113     int mid = (l + r) >> 1 , ans = 0;
114     if(b <= mid)
115         ans += query(b , e , lson);
116     if(e > mid)
117         ans += query(b , e , rson);
118     if(b <= mid && e > mid && rc[x << 1] == lc[x << 1 | 1])
119         ans -- ;
120     return ans;
121 }
122 int getcl(int p , int l , int r , int x)
123 {
124     pushdown(x);
125     if(l == r)
126         return lc[x];
127     int mid = (l + r) >> 1;
128     if(p <= mid)
129         return getcl(p , lson);
130     else
131         return getcl(p , rson);
132 }
133 int solvequery(int x , int y)
134 {
135     int ans = 0;
136     while(bl[x] != bl[y])
137     {
138         if(deep[bl[x]] < deep[bl[y]])
139             swap(x , y);
140         ans += query(pos[bl[x]] , pos[x] , 1 , n , 1);
141         if(getcl(pos[bl[x]] , 1 , n , 1) == getcl(pos[fa[bl[x]]] , 1 , n , 1))
142             ans -- ;
143         x = fa[bl[x]];
144     }
145     if(deep[x] > deep[y])
146         swap(x , y);
147     ans += query(pos[x] , pos[y] , 1 , n , 1);
148     return ans;
149 }
150 int main()
151 {
152     int i , x , y , z , m;
153     scanf("%d%d" , &n , &m);
154     for(i = 1 ; i <= n ; i ++ )
155         scanf("%d" , &val[i]);
156     for(i = 1 ; i < n ; i ++ )
157     {
158         scanf("%d%d" , &x , &y);
159         add(x , y);
160         add(y , x);
161     }
162     dfs1(1);
163     dfs2(1 , 1);
164     for(i = 1 ; i <= n ; i ++ )
165         update(pos[i] , pos[i] , val[i] , 1 , n , 1);
166     while(m -- )
167     {
168         scanf("%s" , str);
169         switch(str[0])
170         {
171             case ‘C‘: scanf("%d%d%d" , &x , &y , &z); solveupdate(x , y , z); break;
172             default: scanf("%d%d" , &x , &y); printf("%d\n" , solvequery(x , y));
173         }
174     }
175     return 0;
176 }
时间: 2024-08-14 05:40:52

【bzoj2243】[SDOI2011]染色的相关文章

bzoj2243 [SDOI2011]染色 动态树

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 110000 int pre[N],ch[N][2]; int e[N],ne[N*2],v[N*2]; int nn,m; int col[N]; int lc[N],sm[N],rc[N],num[N]; int rt[N],n; int qu[N

BZOJ2243 [SDOI2011]染色

题意:树,路径染色,路径查询分了几段. 分析: 树链剖分套线段树,没写过,代码写得很乱,还犯了不少错,加了点注释,以后不能犯这种错了. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define m ((L+R)>>1) #define lc o<<1 #define rc o<<1|1 #define ls lc,L,m

[BZOJ2243][SDOI2011]染色 解题报告|树链剖分

Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. 与上一题差别不大,主要就是solve过程要根据左端点和右端点的颜色处理合并时候的情况 线段树的每个节点要记录颜色段数|最左边的颜色|最右边的颜色 同时往下传的时候标记要做好(之前那道题是单点修改所以不用考虑

BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

题目链接 BZOJ2243 树链剖分+线段树合并 线段树合并的一些细节需要注意一下 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 100010; int n, m,

bzoj2243: [SDOI2011]染色 树链剖分

裸树剖. #include<bits/stdc++.h> using namespace std; #define N 100010 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define L l,M,P #define R M+1,r,S #define Z int l=1,int r=n,int k=1 typedef int ds[N]; ds dp,num,p,size,son,t

bzoj2243 sdoi2011 染色 paint

明明是裸树剖 竟然调了这么久好蛋疼 大概是自己比较水的原因吧 顺便+fastio来gangbang #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cstdio> #include<cctype> using namespace std; const int Maxn=100010,Maxm=Maxn; int n,

[BZOJ2243]SDOI2011染色|树链剖分|LCT

裸题嘛.. 先考虑一条线段上如何查询颜色段数,只要对每个线段树节点多维护一个左颜色和右颜色,然后合并的时候sum[x]=sum[lc]+sum[rc]-(左儿子的右颜色==右儿子的左颜色)..实在太久没写树剖结果码+调试花了两节多晚自习,,各种傻逼错误,什么反向边忘加,标记忘记下传...还有就是更新答案的时候,关键的一点是要保证当前的两点(也就是a,b)是没有被更新到的,否则很难搞.. 表示LCT要更好写..不过在BZOJ上我的树链剖分6000+MS,LCT要13000+MS.. 树链剖分: #

【树链剖分】bzoj2243 [SDOI2011]染色

树链剖分模板题.线段树维护每个段中的颜色数.左端点颜色.右端点颜色. pushup: col[rt]=col[rt<<1]+col[rt<<1|1]-(Rcol[rt<<1]==Lcol[rt<<1|1]); 在合并各个链的答案时,要注意若两头颜色相同,ans--. [教训:树链剖分题在进行建立线段树树时,要注意下面代码中的标注部分.否则会WA] Code: 1 #include<cstdio> 2 #include<algorithm&g

bzoj2243: [SDOI2011]染色--线段树+树链剖分

此题代码量较大..但是打起来很爽 原本不用lca做一直wa不知道为什么.. 后来改lca重打了一遍= =结果一遍就AC了orz 题目比较裸,也挺容易打,主要是因为思路可以比较清晰 另:加读入优化比没加快了1.3s.. 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 100010; 6 struct node{

[BZOJ2243][SDOI2011]染色(树链剖分)

[传送门] 树链剖分就行了,注意线段树上颜色的合并 Code #include <cstdio> #include <algorithm> #define N 100010 #define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1 #define len (r-l+1) using namespace std; struct tree{ int lc,rc,sum,tag; tree(){lc=rc=tag