2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9954 Solved: 3773
[ Submit][ Status][ Discuss]
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
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
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
Source
【思路】
基本操作,赛前练手。把树按轻重链剖分,然后用线段树实现区间合并。
线段树的每个节点记录最左的节点颜色、最右的节点颜色、区间内色段树,遇到接缝处颜色一样的情况就减一。
【代码】
//****************************************************************************** // File Name: HYSBZ_2243.cpp // Author: Shili_Xu // E-Mail: [email protected] // Created Time: 2018年05月16日 星期三 20时09分19秒 //****************************************************************************** #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; typedef long long ll; const int MAXN = 1e5 + 5; struct edge { int from, to; edge() {} edge(int u, int v) : from(u), to(v) {} }; struct segment { int l, r; int lx, rx, cnt, mark; }; int n, m, tot; vector<edge> e; vector<int> g[MAXN]; segment tree[MAXN << 2]; int fa[MAXN], top[MAXN], deep[MAXN], sz[MAXN], max_son[MAXN], in[MAXN]; int id[MAXN], connect[MAXN], a[MAXN]; void add_edge(int u, int v) { e.push_back(edge(u, v)); g[u].push_back(e.size() - 1); } void dfs_1(int u, int f, int d) { fa[u] = f; deep[u] = d; sz[u] = 1; max_son[u] = 0; for (int i = 0; i < g[u].size(); i++) { edge &now = e[g[u][i]]; if (now.to == f) continue; dfs_1(now.to, u, d + 1); if (sz[max_son[u]] < sz[now.to]) max_son[u] = now.to; sz[u] += sz[now.to]; } } void dfs_2(int u, int tp) { top[u] = tp; in[u] = ++tot; id[tot] = u; if (max_son[u]) dfs_2(max_son[u], tp); for (int i = 0; i < g[u].size(); i++) { edge &now = e[g[u][i]]; if (now.to == fa[u] || now.to == max_son[u]) continue; dfs_2(now.to, now.to); } } void push_up(int root) { tree[root].lx = tree[root << 1].lx; tree[root].rx = tree[root << 1 | 1].rx; tree[root].cnt = tree[root << 1].cnt + tree[root << 1 | 1].cnt; if (tree[root << 1].rx == tree[root << 1 | 1].lx) tree[root].cnt--; } void push_down(int root) { int mark = tree[root].mark; if (mark != -1) { tree[root << 1].mark = tree[root << 1 | 1].mark = mark; tree[root << 1].cnt = tree[root << 1 | 1].cnt = 1; tree[root << 1].lx = tree[root << 1].rx = mark; tree[root << 1 | 1].lx = tree[root << 1 | 1].rx = mark; tree[root].mark = -1; } } void build(int left, int right, int root) { tree[root].l = left; tree[root].r = right; tree[root].mark = -1; int mid = (left + right) >> 1; if (left == right) { tree[root].lx = tree[root].rx = a[id[mid]]; tree[root].cnt = 1; return; } build(left, mid, root << 1); build(mid + 1, right, root << 1 | 1); push_up(root); } void modify(int left, int right, int color, int root) { if (left <= tree[root].l && tree[root].r <= right) { tree[root].mark = tree[root].lx = tree[root].rx = color; tree[root].cnt = 1; return; } push_down(root); int mid = (tree[root].l + tree[root].r) >> 1; if (left <= mid) modify(left, right, color, root << 1); if (right >= mid + 1) modify(left, right, color, root << 1 | 1); push_up(root); } int query(int left, int right, int root) { if (left <= tree[root].l && tree[root].r <= right) return tree[root].cnt; push_down(root); int mid = (tree[root].l + tree[root].r) >> 1; int ans = 0; if (left <= mid) ans += query(left, right, root << 1); if (right >= mid + 1) ans += query(left, right, root << 1 | 1); if (left <= mid && right >= mid + 1 && tree[root << 1].rx == tree[root << 1 | 1].lx) ans--; return ans; } int find_color(int pos, int root) { if (tree[root].l == tree[root].r) return tree[root].lx; push_down(root); int mid = (tree[root].l + tree[root].r) >> 1; if (pos <= mid) return find_color(pos, root << 1); if (pos >= mid + 1) return find_color(pos, root << 1 | 1); } int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n - 1; i++) { int u, v; scanf("%d %d", &u, &v); add_edge(u, v); add_edge(v, u); } dfs_1(1, 0, 0); dfs_2(1, 1); build(1, n, 1); char mes[2]; while (m--) { scanf("%s", mes); if (mes[0] == 'C') { int u, v, c; scanf("%d %d %d", &u, &v, &c); while (top[u] != top[v]) { if (deep[top[u]] < deep[top[v]]) swap(u, v); modify(in[top[u]], in[u], c, 1); u = fa[top[u]]; } if (deep[u] < deep[v]) swap(u, v); modify(in[v], in[u], c, 1); } if (mes[0] == 'Q') { int u, v; scanf("%d %d", &u, &v); int ans = 0; while (top[u] != top[v]) { if (deep[top[u]] < deep[top[v]]) swap(u, v); ans += query(in[top[u]], in[u], 1); if (find_color(in[top[u]], 1) == find_color(in[fa[top[u]]], 1)) ans--; u = fa[top[u]]; } if (deep[u] < deep[v]) swap(u, v); ans += query(in[v], in[u], 1); printf("%d\n", ans); } } return 0; }