您的位置:首页 > 其它

【bzoj2243】[SDOI2011]染色

2017-03-14 14:38 344 查看
题目链接

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

题解

直接树剖加线段树,维护区间颜色段数量,最左端颜色,最右端颜色,和覆盖标记。

对于x,y的操作转化为对于x,lca(x, y)和y,lca(x, y)的操作。

线段数在合并时注意如果左子区间的右端颜色和右子区间的左端颜色相同则减一。树链剖分是若当前重链顶和其父亲颜色相同再减一。最后查询的答案是将x,lca(x, y)和y,lca(x, y)的答案相加并直接减一。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
const int N = 100000 + 10, M = 200000 + 10;
int v
;
int to[M], nxt[M], hd
;
int dep
, siz
, bl
, pos
, fa
, son
, id
;
int n, m, tot, sz;
struct Seg{
int l, r;
}t[M<<1];
int cov[M<<1], l_cl[M<<1], r_cl[M<<1], sum[M<<1];

void insert(int u, int v){
to[++tot] = v; nxt[tot] = hd[u]; hd[u] = tot;
to[++tot] = u; nxt[tot] = hd[v]; hd[v] = tot;
}
inline void in(int &x){
x = 0; int f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
x *= f;
}
void init(){
in(n); in(m);
for(int i = 1; i <= n; i++) in(v[i]);
for(int i = 1; i < n; i++){
int x, y;
in(x); in(y);
insert(x, y);
}
}
void dfs1(int x){
siz[x] = 1;
for(int i = hd[x]; i; i = nxt[i]){
if(to[i] == fa[x]) continue;
dep[to[i]] = dep[x] + 1;
fa[to[i]] = x;
dfs1(to[i]);
if(siz[to[i]] > siz[son[x]]) son[x] = to[i];
siz[x] += siz[to[i]];
}
}
void dfs2(int x, int chain){
pos[x] = ++sz;
id[sz] = x;
bl[x] = chain;
if(!son[x]) return;
dfs2(son[x], chain);
for(int i = hd[x]; i; i = nxt[i])
if(to[i] != fa[x] && to[i] != son[x])
dfs2(to[i], to[i]);
}
int Lca(int x, int y){
while(bl[x] != bl[y]){
if(pos[bl[x]] < pos[bl[y]]) swap(x, y);
x = fa[bl[x]];
}
return pos[x] < pos[y] ? x : y;
}

void pup(int o){
l_cl[o] = l_cl[lc]; r_cl[o] = r_cl[rc];
sum[o] = sum[lc] + sum[rc] - (r_cl[lc] == l_cl[rc]);
}
void pdw(int o){
if(cov[o] == -1 || t[o].l == t[o].r) return;
sum[lc] = sum[rc] = 1;
cov[lc] = cov[rc] = cov[o];
l_cl[lc] = r_cl[lc] = l_cl[rc] = r_cl[rc] = cov[o];
cov[o] = -1;
}
void build(int o, int l, int r){
t[o].l = l; t[o].r = r; sum[o] = 1; cov[o] = -1;
if(l == r){
l_cl[o] = r_cl[o] = cov[o] = v[id[l]];
return;
}
int mid = (l + r) >&
4000
gt; 1;
build(lc, l, mid); build(rc, mid+1, r);
pup(o);
}
void change(int o, int x, int y, int c){
pdw(o);
int l = t[o].l, r = t[o].r, mid = (l + r) >> 1;
if(l == x && r == y) { l_cl[o] = r_cl[o] = cov[o] = c; sum[o] = 1; return; }
if(y <= mid) change(lc, x, y, c);
else if(x > mid) change(rc, x, y, c);
else change(lc, x, mid, c), change(rc, mid+1, y, c);
pup(o);
}
int query(int o, int x, int y){
pdw(o);
int l = t[o].l, r = t[o].r, mid = (l + r) >> 1;
if(l == x && r == y) return sum[o];
if(y <= mid) return query(lc, x, y);
else if(x > mid) return query(rc, x, y);
else return query(lc, x, mid) + query(rc, mid+1, y) - (r_cl[lc] == l_cl[rc]);
}
int getc(int o, int x){
pdw(o);
int l = t[o].l, r = t[o].r, mid = (l + r) >> 1;
if(l == r) return l_cl[o];
if(x <= mid) return getc(lc, x);
else return getc(rc, x);
}

int solvesum(int x, int f){
int cnt = 0;
while(bl[x] != bl[f]){
cnt += query(1, pos[bl[x]], pos[x]) - (getc(1, pos[bl[x]]) == getc(1, pos[fa[bl[x]]]));
x = fa[bl[x]];
}
cnt += query(1, pos[f], pos[x]);
return cnt;
}
void solvechange(int x, int f, int c){
while(bl[x] != bl[f]){
change(1, pos[bl[x]], pos[x], c);
x = fa[bl[x]];
}
change(1, pos[f], pos[x], c);
}
void work(){
build(1, 1, n);
char s[20];
int a, b, c;
for(int i = 1; i <= m; i++){
scanf("%s", s);
if(s[0] == 'C'){
in(a); in(b); in(c);
int t = Lca(a, b);
solvechange(a, t, c);
solvechange(b, t, c);
}
else{
in(a); in(b);
int t = Lca(a, b);
printf("%d\n", solvesum(a, t) + solvesum(b, t) - 1);
}
}
}
int main(){
init();
dfs1(1);
dfs2(1, 1);
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: