洛谷 P2486 [SDOI2011]染色
树链剖分裸题。
线段树统计“答案”、“前缀字符”、“后缀字符”三个信息就可以很方便的合并了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int n, m;
int head[maxn], nxt[maxn * 4], to[maxn * 4], cnt;
void inline addEdge(int u, int v) {
nxt[++cnt] = head[u], to[cnt] = v, head[u] = cnt;
nxt[++cnt] = head[v], to[cnt] = u, head[v] = cnt;
}
namespace Tree
{
// PartI. Tree
int col[maxn], son[maxn], fa[maxn], top[maxn], size[maxn], deep[maxn], dfn[maxn], org[maxn], dfs_clock;
void dfs1(int u, int pa) {
fa[u] = pa; deep[u] = deep[pa] + 1;
size[u] = 1;
for(int e = head[u]; e; e = nxt[e]) {
int v = to[e];
if(v == pa) continue;
dfs1(v, u);
size[u] += size[v];
if(size[v] > size[son[u]]) son[u] = v;
}
}
void dfs2(int u, int pa) {
dfn[u] = ++dfs_clock;
org[dfs_clock] = u;
if(son[u]) {
top[son[u]] = top[u];
dfs2(son[u], u);
}
for(int e = head[u]; e; e = nxt[e]) {
int v = to[e];
if(v == son[u] || v == pa) continue;
top[v] = v;
dfs2(v, u);
}
}
// PartII. Segment
struct Node {
int val;
int color[2];
Node() { val = color[0] = color[1] = 0; }
} node[maxn * 4];
int tag[maxn * 4];
Node inline merge(Node left, Node right)
{
Node ans;
ans.val = left.val + right.val - (left.color[1] == right.color[0]);
ans.color[0] = left.color[0], ans.color[1] = right.color[1];
return ans;
}
void inline pushup(int id) {
node[id] = merge(node[id << 1], node[id << 1 | 1]);
}
void inline pushdown(int id) {
if(tag[id]) {
tag[id << 1] = tag[id << 1 | 1] = tag[id];
node[id << 1].val = node[id << 1 | 1].val = 1;
node[id << 1].color[0] = node[id << 1].color[1] = node[id << 1 | 1].color[0] = node[id << 1 | 1].color[1] = tag[id];
tag[id] = 0;
}
}
void build(int id, int l, int r) {
if(l == r) {
node[id].val = 1, node[id].color[0] = node[id].color[1] = col[org[l]];
return;
}
int mid = l + r >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
}
Node query(int id, int l, int r, int s, int t) {
if(s <= l && t >= r) {
return node[id];
}
int mid = l + r >> 1;
pushdown(id); Node ansl, ansr;
if(s <= mid) { ansl = query(id << 1, l, mid, s, t); if(t <= mid) return ansl; }
if(t > mid) { ansr = query(id << 1 | 1, mid + 1, r, s, t); if(s > mid) return ansr; }
return merge(ansl, ansr);
}
void rset(int id, int l, int r, int s, int t, int v) {
if(s <= l && t >= r) {
tag[id] = node[id].color[0] = node[id].color[1] = v;
node[id].val = 1;
return;
}
int mid = l + r >> 1;
pushdown(id);
if(s <= mid) rset(id << 1, l, mid, s, t, v);
if(t > mid) rset(id << 1 | 1, mid + 1, r, s ,t ,v);
pushup(id);
}
}
using namespace Tree;
void inline Init()
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", col + i);
int u, v;
for(int i = 1; i < n; ++i) {
scanf("%d %d", &u, &v);
addEdge(u, v);
}
dfs1(1, 0);
top[1] = 1;
dfs2(1, 0);
build(1, 1, n);
}
char opt[5]; int x, y, v;
void inline Solve()
{
while(m--) {
scanf("%s %d %d", opt, &x, &y);
if(opt[0] == 'C') {
scanf("%d", &v);
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x, y);
rset(1, 1, n, dfn[top[x]], dfn[x], v);
x = fa[top[x]];
}
if(deep[x] > deep[y]) swap(x, y);
rset(1, 1, n, dfn[x], dfn[y], v);
} else {
Node ansl, ansr;
while(top[x] != top[y]) {
if(deep[top[x]] > deep[top[y]]) {
ansl = merge(query(1, 1, n, dfn[top[x]], dfn[x]), ansl);
x = fa[top[x]];
} else {
ansr = merge(query(1, 1, n, dfn[top[y]], dfn[y]), ansr);
y = fa[top[y]];
}
}
if(deep[x] > deep[y]) {
ansl = merge(query(1, 1, n, dfn[y], dfn[x]), ansl);
} else {
ansr = merge(query(1 ,1, n, dfn[x], dfn[y]), ansr);
}
swap(ansl.color[0], ansl.color[1]);
printf("%d\n", merge(ansl, ansr).val);
}
}
}
int main()
{
Init();
Solve();
return 0;
}