题意

对一个树上维护两种操作,一种是把x到y间的点都染成c色,另一种是求x到y间的点有多少个颜色块,比如112221由“11”,“222”,“1”三块组成。

思路

这题的关键是要如何维护这个颜色块,我们可以利用线段树,记录每个区间的块数,区间左端点,区间右端点的颜色。合并中如果两个区间相邻点颜色相同,个数要减去1.
查询也是一样的,链与链间的相邻点也要考虑清楚。

#include <algorithm>
#include <iterator>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <iomanip>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <stack>
#include <cmath>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cassert> /* ⊂_ヽ
  \\ Λ_Λ 来了老弟
   \('ㅅ')
    > ⌒ヽ
   /   へ\
   /  / \\
   レ ノ   ヽ_つ
  / /
  / /|
 ( (ヽ
 | |、\
 | 丿 \ ⌒)
 | |  ) /
'ノ )  Lノ */ using namespace std;
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "\n";
#define pb push_back
#define pq priority_queue typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 bll;
typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl '\n' #define boost ios::sync_with_stdio(false);cin.tie(0)
#define rep(a, b, c) for(int a = (b); a <= (c); ++ a)
#define max3(a,b,c) max(max(a,b), c);
#define min3(a,b,c) min(min(a,b), c); const ll oo = 1ll<<;
const ll mos = 0x7FFFFFFF; //
const ll nmos = 0x80000000; //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f; //
const ll mod = ;
const double esp = 1e-;
const double PI=acos(-1.0);
const double PHI=0.61803399; //黄金分割点
const double tPHI=0.38196601; template<typename T>
inline T read(T&x){
x=;int f=;char ch=getchar();
while (ch<''||ch>'') f|=(ch=='-'),ch=getchar();
while (ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
return x=f?-x:x;
} inline void cmax(int &x,int y){if(x<y)x=y;}
inline void cmax(ll &x,ll y){if(x<y)x=y;}
inline void cmin(int &x,int y){if(x>y)x=y;}
inline void cmin(ll &x,ll y){if(x>y)x=y;} /*-----------------------showtime----------------------*/ const int maxn = 1e5+;
int a[maxn],b[maxn];
int dp[maxn],sz[maxn],fa[maxn],son[maxn];
vector<int>mp[maxn]; void dfs1(int u,int f,int deep){
dp[u] = deep;
fa[u] = f;
sz[u] = ;
int mx = ;
for(int i=; i<mp[u].size(); i++){
int v = mp[u][i];
if(v == f) continue;
dfs1(v, u, deep+);
sz[u] += sz[v];
if(sz[v] > mx) {mx = sz[v], son[u] = v;}
}
} int top[maxn],id[maxn],cnt = ;
void dfs2(int u,int f,int topf){
top[u] = topf;
id[u] = ++cnt;
b[cnt] = a[u];
if(son[u])dfs2(son[u], u, topf);
for(int i=; i<mp[u].size(); i++){
int v = mp[u][i];
if(v == f || v == son[u]) continue;
dfs2(v, u, v);
}
} int tag[maxn<<],lazy[maxn<<],ly[maxn<<],rz[maxn<<];
void pushup(int rt){
tag[rt] = tag[rt<<] + tag[rt<<|];
rz[rt] = rz[rt<<];
ly[rt] = ly[rt<<|];
if(ly[rt<<] == rz[rt<<|])tag[rt] --;
}
void build(int l,int r,int rt){
if(l == r){
tag[rt] = ;
ly[rt] = rz[rt] = b[l];
return ;
}
int mid = (l + r) >> ;
build(l, mid, rt<<);
build(mid+,r,rt<<|);
pushup(rt);
// cout<<l<<" "<<r<<" "<<rz[rt] << " " << ly[rt]<<endl;
}
void pushdown(int l,int r,int rt){
tag[rt<<] = tag[rt<<|] = ;
ly[rt<<] = rz[rt<<] = lazy[rt];
ly[rt<<|] = rz[rt<<|] = lazy[rt];
lazy[rt<<] = lazy[rt<<|] = lazy[rt];
lazy[rt] = ;
}
void update(int L, int R, int c, int l, int r,int rt){
if(l >= L && r <= R){
tag[rt] = ;
ly[rt] = rz[rt] = c;
lazy[rt] = c;
return;
}
int mid = (l + r) >> ;
if(lazy[rt]) pushdown(l, r, rt);
if(mid >= L) update(L, R, c, l, mid, rt<<);
if(mid < R) update(L,R,c,mid+,r,rt<<|);
pushup(rt);
}
int n,m;
void solve(int x,int y,int c){
while(top[x] != top[y]){
if(dp[top[x]] < dp[top[y]]) swap(x, y);
update(id[top[x]], id[x], c, , n, );
x = fa[top[x]];
}
if(dp[x] > dp[y]) swap(x, y);
update(id[x], id[y], c, , n, );
} int query(int L,int R, int l,int r,int rt,int &tmpl,int &tmpr){
if(l >= L && r<= R){
if(l == L) tmpl = rz[rt];
if(r == R) tmpr = ly[rt]; return tag[rt];
}
int mid = (l + r) >> ;
if(lazy[rt])pushdown(l, r, rt);
int res = ;
int ql = -, qr = -;
if(mid >= L) {
res += query(L, R, l, mid, rt<<,tmpl,tmpr);
ql = ly[rt<<];
}
if(mid < R){
res += query(L, R, mid +, r, rt<<|,tmpl,tmpr);
qr = rz[rt<<|];
}
if(ql == qr && ql != -) res --;
pushup(rt);
return res;
}
int cal(int x,int y){
int res = ,lax = -,lay=-; while(top[x] != top[y]){
int tmpl = -,tmpr=-;
if(dp[top[x]] > dp[top[y]]) {
res += query(id[top[x]], id[x], , n, , tmpl, tmpr);//tmp,flag 1,r
if(lax == tmpr) res--;
lax = tmpl;
x = fa[top[x]];
}
else {
res += query(id[top[y]], id[y], , n, ,tmpl,tmpr);
if(lay == tmpr) res--;
lay = tmpl;
y = fa[top[y]];
} // cout<<tmpl<<" !! "<<tmpr<<endl;
} if(dp[x] > dp[y]){
int tmpl = -,tmpr=-;
res += query(id[y], id[x], , n, ,tmpl,tmpr);
if(tmpr == lax) res--;
if(tmpl == lay) res--;
}
else {
int tmpl = -,tmpr=-;
res += query(id[x], id[y], , n, ,tmpl,tmpr);
if(tmpl == lax) res--;
if(tmpr == lay) res--;
} return res;
}
int main(){
scanf("%d%d", &n, &m);
rep(i, , n) scanf("%d", &a[i]);
rep(i, , n-) {
int u,v;
scanf("%d%d", &u, &v);
mp[u].pb(v);
mp[v].pb(u);
}
dfs1(, , );
dfs2(, , );
build(, n, ); while(m--){
char str[];
scanf("%s", str);
if(str[] == 'C') {
int x,y,z;
scanf("%d%d%d", &x, &y, &z);
solve(x, y, z);
}
else {
int x,y;
scanf("%d%d", &x, &y);
printf("%d\n", cal (x,y));
} }
return ;
}

P2486 [SDOI2011]染色 维护区间块数 树链剖分的更多相关文章

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

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

  2. P2486 [SDOI2011]染色 区间合并+树链剖分(加深对线段树的理解)

    #include<bits/stdc++.h> using namespace std; ; struct node{ int l,r,cnt,lazy; node(,,,):l(l1), ...

  3. P2486 [SDOI2011]染色 区间合并+树链剖分(加深对线段树的理解)

    #include<bits/stdc++.h> using namespace std; ; struct node{ int l,r,cnt,lazy; node(,,,):l(l1), ...

  4. 2020牛客NOIP赛前集训营-提高组(第三场) C - 牛半仙的妹子Tree (树链剖分)

    昨天教练问我:你用树剖做这道题,怎么全部清空状态呢?    我:???不是懒标记就完了???    教练:树剖不是要建很多棵线段树吗,不止log个,你要一个一个清?    我:为什么要建很多棵线段树? ...

  5. luogu题解 P3950部落冲突--树链剖分

    题目链接 https://www.luogu.org/problemnew/show/P3950 分析 大佬都用LCT,我太弱只会树链剖分 一个很裸的维护边权树链剖分题.按照套路,对于一条边\(< ...

  6. Luogu P2486 [SDOI2011]染色(树链剖分+线段树合并)

    Luogu P2486 [SDOI2011]染色 题面 题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例: 6 5 2 2 1 2 1 1 1 ...

  7. 洛谷 P2486 [SDOI2011]染色 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 PushDown与Update Q AC代码 总结与拓展 题面 题目链接 P2486 ...

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

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

  9. P2486 [SDOI2011]染色(树剖)区间覆盖+区间的连续段

    https://www.luogu.org/problemnew/show/P2486 值的一看https://www.cnblogs.com/Tony-Double-Sky/p/9283262.ht ...

随机推荐

  1. Java计时新姿势

    为获得更好的阅读体验,请访问原文:传送门 前言: 最近公司来了个大佬,从他那里学到不少东西,其中一个就是计时 的新姿势「StopWatch」,赶紧来一起了解了解吧! 一.最简单的计时 在我们的程序中不 ...

  2. 【iOS】iOS viewDidLoad 方法名问题

    这两天在调试一个项目,跳转到一个页面的时候总是不显示标题栏(当然也没有标题栏的返回按钮),搞了好久,今天总算找到了问题:之前的开发人员竟然把 viewDidLoad 这个基本的方法名写成了 views ...

  3. 算法与数据结构基础 - 哈希表(Hash Table)

    Hash Table基础 哈希表(Hash Table)是常用的数据结构,其运用哈希函数(hash function)实现映射,内部使用开放定址.拉链法等方式解决哈希冲突,使得读写时间复杂度平均为O( ...

  4. JAVA基础知识(七)存根类

    存根类是一个类,它实现了一个接口,它的作用是:如果一个接口有很多方法,如果要实现这个接口,就要实现所有的方法.但是一个类从业务来说,可能只需要其中一两个方法.如果直接去实现这个接口,除了实现所需的方法 ...

  5. No!No!No! It's not fashion!

    还记得搞怪的hold住姐Miss Lin么,对于人们常规的行为,Miss Lin会挑起夸张的眉毛说:"Oh my God, it's not fashion!".如果程序员圈子里有 ...

  6. javaweb基础整理随笔-----上传与下载步骤详解

    这次整理的是上传与下载的原生代码解析: 上传:1.对页面的要求:enctype="multipart/form-data" method="post"      ...

  7. Mock Server的搭建

    一.概述 我们系统与第三方开票系统有交互,场景是我们系统请求第三方开票系统,第三方开票系统根据我们的请求数据,生成开票信息然后返回发票号或异常信息,我们根据返回的信息做对应的处理.因为配合上存在一些障 ...

  8. 《深入理解Java虚拟机》- Java虚拟机是如何加载Java类的?

    Java虚拟机是如何加载Java类的?  这个问题也就是面试常问到的Java类加载机制.在年初面试百战之后,菜鸟喜鹊也是能把这流程倒背如流啊!但是,也只是字面上的背诵,根本就是像上学时背书考试一样. ...

  9. 重学计算机组成原理(七)- 程序无法同时在Linux和Windows下运行?

    既然程序最终都被变成了一条条机器码去执行,那为什么同一个程序,在同一台计算机上,在Linux下可以运行,而在Windows下却不行呢? 反过来,Windows上的程序在Linux上也是一样不能执行的 ...

  10. Python 获取服务器的CPU个数

    在使用gunicorn时,需要设置workers, 例如: gunicorn --workers=3 app:app -b 0.0.0.0:9000 其中,worker的数量并不是越多越好,推荐值是C ...