Description
给定一棵树,树节点编号为 0~N-1 的,根的节点编号为 0,每个节点有初始颜色 c 和权值 v,现在有三种操作:
1.Change u x y,表示将 u 的子树中颜色为 x 和 y 的节点颜色反转,即将 x 颜色的的节点换成 y 颜色,将 y 颜色的节点换成 x 颜色。数据保证 x 与 y 不相等。
2.Ask u v c,表示询问 u 到 v 的路径上,颜色为 c 的节点的权值之和。
3.Set u c val,表示将节点 u 的颜色设置为 c,权值设置为 val。
Input
第一行有一个整数 N,表示树的节点数。
第二行有 N 个整数 c_i,表示每个节点的颜色。
第三行有 N 个整数 v_i,表示每个节点的权值。
接下来 N-1 行,每行两个整数 x 和 y,表示 x 和 y 有一条直接连边。
接下来一行有一个整数 M,表示操作数。
接下来 M 行,每行输入格式参照问题描述。
Output
对于每一次询问,输出一行。
样例1
3
0 1 2
0 1 2
0 1
0 2
4
Ask 1 2 0
Change 0 1 2
Set 0 1 98
Ask 1 2 1
样例2
3
0 1 2
0 1 2
0 1
0 2
4
Ask 1 2 1
Change 0 1 2
Set 0 1 98
Ask 1 2 2
Sample Input
样例1
0
100
样例2
1
1
Sample Output
HINT
对于 20%数据,N<=1000 M<=1000
对于 50%数据,N<=10000 M<=10000 0<=c_i<2 0<=xy<2 0<=c<2
对于 100%数据,N<=50000 M<=50000 0<=c_i<10 |v_i|<=10000 0<=uv
Source/Category
GDKOI2015
直接一看,树链剖分板子,但是有些很烦人的细节.
#include
#include
#include
using namespace std;
const int MAXN = 50010;
typedef long long ll;
struct edge { // 定义一个边
int v, nxt;
} ed[MAXN<<1];
int n, depth[MAXN], dfn[MAXN], revdfn[MAXN], top[MAXN], son[MAXN], tsize[MAXN], fa[MAXN], dfstime; // 树链剖分的一大堆东西
ll cnt[MAXN<<2][12]; pair tag[MAXN<<2]; // 线段树的一大堆东西
int c[MAXN], head[MAXN], id[MAXN<<2], ed_cnt=0; // 建图要的一大堆东西
ll w[MAXN];
/*int l[MAXN<<2], r[MAXN<<2];*/
void addedge(int u, int v) { // 加边
ed[++ed_cnt].v = v; ed[ed_cnt].nxt = head[u]; head[u] = ed_cnt;
ed[++ed_cnt].v = u; ed[ed_cnt].nxt = head[v]; head[v] = ed_cnt;
}
void dfs(int u, int pa, int dep) { // 树链剖分的第一次深搜
fa[u] = pa; tsize[u] = 1; son[u] = 0; depth[u] = dep; // 获得祖先深度,初始化大小重儿子
for (int i=head[u]; i; i=ed[i].nxt) {
int v = ed[i].v; if (v==pa) continue; // 确保不会跳回祖先
dfs(v, u, dep+1); tsize[u] += tsize[v]; // 更新字树大小
if (tsize[v]>tsize[son[u]]) son[u] = v; // 更新重儿子
}
}
void dfs2(int u, int tp) { // 树链剖分的第二次深搜
top[u] = tp; dfn[u] = ++dfstime; revdfn[dfstime] = u; // 获得重链顶时间戳
if (son[u]) { // 如果有儿子
dfs2(son[u], tp); // 先递归重儿子
for (int i=head[u]; i; i=ed[i].nxt) { // 枚举轻儿子递归
int v = ed[i].v; if ((v==fa[u]) || (v==son[u])) continue;
dfs2(v, v);
}
}
}
void build(int rt, int l, int r) { // 线段树构建
// ::l[rt] = l; ::r[rt] = r;
tag[rt] = (pair){-1,-1}; // 初始化懒标记
if (l==r) { // 到达边界
cnt[rt][c[revdfn[l]]] = w[revdfn[l]]; id[rt] = revdfn[l]; return; // 初始化
}
int m = (l+r)>>1;
build(rt<<1, l, m); build(rt<<1|1, m+1, r);
for (int i=0; i<10; ++i) cnt[rt][i] = cnt[rt<<1][i]+cnt[rt<<1|1][i];
}
void pushdown(int rt, int l, int r) { // 烦人的下传懒标记
if (tag[rt].first!=-1) { // 如果有懒标记
if (l> 1;
pushdown(rt<<1, l, m); pushdown(rt<<1|1, m+1, r); // 左右下传,防止懒标记被覆盖
int x = tag[rt].first, y = tag[rt].second;
swap(cnt[rt<<1][x], cnt[rt<<1][y]); // 交换和
tag[rt<<1] = tag[rt]; // 下传
if (id[rt<<1]) { // 改变颜色数组
if (c[id[rt<<1]]==x) c[id[rt<<1]] = y;
else if (c[id[rt<<1]]==y) c[id[rt<<1]] = x;
}
swap(cnt[rt<<1|1][x], cnt[rt<<1|1][y]); // 右儿子的同上
tag[rt<<1|1] = tag[rt];
if (id[rt<<1|1]) {
if (c[id[rt<<1|1]]==x) c[id[rt<<1|1]] = y;
else if (c[id[rt<<1|1]]==y) c[id[rt<<1|1]] = x;
}
}
tag[rt] = (pair){-1,-1}; // 清空懒标记
}
}
void update_swap(int rt, int l, int r, int x, int y, int k, int k2) { // 交换
pushdown(rt, l, r);
if ((x<=l) && (r<=y)) { // 完全包括,设懒标记
swap(cnt[rt][k], cnt[rt][k2]); tag[rt] = (pair){k,k2}; return;
}
int m = (l+r) >> 1;
if (x<=m) update_swap(rt<<1, l, m, x, y, k, k2);
if (y>m) update_swap(rt<<1|1, m+1, r, x, y, k, k2);
for (int i=0; i<10; ++i) cnt[rt][i] = cnt[rt<<1][i]+cnt[rt<<1|1][i]; // 上传
}
void update(int rt, int l, int r, int x, int cc, ll val) { // 更新单点信息
pushdown(rt, l, r);
if (l==r) {
cnt[rt][c[revdfn[l]]] = 0LL; c[revdfn[l]] = cc;
cnt[rt][cc] = val; return;
}
int m = (l+r) >> 1;
if (x<=m) update(rt<<1, l, m, x, cc, val);
else update(rt<<1|1, m+1, r, x, cc, val);
for (int i=0; i<10; ++i) cnt[rt][i] = cnt[rt<<1][i]+cnt[rt<<1|1][i]; // 上传
}
ll query(int rt, int l, int r, int x, int y, int cc) { // 查询
pushdown(rt, l, r);
if ((x<=l) && (r<=y)) return cnt[rt][cc];
ll res = 0LL;
int m = (l+r) >> 1;
if (x<=m) res += query(rt<<1, l, m, x, y, cc);
if (y>m) res += query(rt<<1|1, m+1, r, x, y, cc);
return res;
}
void Change(int u, int x, int y) { // 子树交换,更新子树
if (x==y) return;
update_swap(1, 1, n, dfn[u], dfn[u]+tsize[u]-1, x, y);
// printf("#Swap l=%d r=%d x=%d y=%d\n", dfn[u], dfn[u]+tsize[u]-1, x, y);
}
ll Ask(int u, int v, int c) { // 路径查询
ll res = 0LL;
while (top[u]!=top[v]) {
if (depth[top[u]]depth[v]) swap(u, v);
// printf("#Ask l=%d r=%d c=%d\n", dfn[u], dfn[v], c);
return res+query(1, 1, n, dfn[u], dfn[v], c);
}
void Set(int u, int c, ll val) { // 单点修改
update(1, 1, n, dfn[u], c, val);
// printf("#Set u=%d c=%d val=%lld\n", dfn[u], c, val);
}
/*
void print() { // 调试
printf("----------");
for (int i=1; i