题意

对一个树上维护两种操作,一种是把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. 【MySQL】添加多个字段

    MySQL 遇到了添加多个字段的问题,尝试了几次,搞定了,记录下. 示例代码如下: alter table ad_data add ( exposure_count bigint(20) defaul ...

  2. Java的编译原理

    概述 java语言的"编译期"分为前端编译和后端编译两个阶段.前端编译是指把*.java文件转变成*.class文件的过程; 后端编译(JIT, Just In Time Comp ...

  3. thinkphp3.2集成极光推送

    项目中用到了给客户端的推送功能,选用了极光推送,下面演示一下在thinkphp中集成极光推送 1.下载极光推送的php类,可以从笔者的git下载 地址:https://git.oschina.net/ ...

  4. 90后iOS开发者的出路,如何规划30岁前的自己(程序员必修课)

    前言: 最近发生了一些和我们没有直接关系但是有间接关系的事情.比如华为“清洗”高龄基层员工,比如游戏公司2号员工拿不到股份而离职.先不说事实到底如何,起码很多码农是心有戚戚焉. 最近一年多也发生了一些 ...

  5. 洛谷P2630 题解

    我先讲一下我的思路 将A,B,C,D四种操作用函数储存起来: 枚举所有可能出现的情况:A,B,C,D,AA,AB,AC,AD,BB,BC,BD,CC,CD,DD,ABC,ABD,ACD,BCD,ABC ...

  6. java并发编程(三)----线程的同步

    在现实开发中,我们或多或少的都经历过这样的情景:某一个变量被多个用户并发式的访问并修改,如何保证该变量在并发过程中对每一个用户的正确性呢?今天我们来聊聊线程同步的概念. 一般来说,程序并行化是为了获得 ...

  7. Netty学习(三)-Netty重要接口讲解

    上一节我们写了一个HelloWorld,对于Netty的运行有了一定的了解,知道Netty是如何启动客户端和服务器端.这一节我们简要的讲解一下几个重要的接口,初步探讨Netty的运行机制,当然刚学Ne ...

  8. 2019牛客多校训练第四场K.number(思维)

    题目传送门 题意: 输入一个只包含数字的字符串,求出是300的倍数的子串的个数(不同位置的0.00.000等都算,并考虑前导零的情况). sample input: 600 1230003210132 ...

  9. 调用链系列(3):如何从零开始捕获body和header

    拓展阅读:调用链系列(1):解读UAVStack中的贪吃蛇 调用链系列(2):轻调用链实现 在Java中,HTTP协议的请求/响应模型是由Servlet规范+Servlet容器(如Tomcat)实现的 ...

  10. Python模块之pysnooper

    一.简介 调试程序时,很多人喜欢直接用print来代替断点调试,而pysnooper模块比print更方便,以装饰器的形式存在 二.实验环境 操作系统:win10 python版本:python3.6 ...