题意
思考
树上链修改,树上链查询,考虑树链剖分
染色操作:线段树区间修改,注意 (lazy) 数组的赋初值
查询操作,线段树每个节点记录该段左端点颜色和右端点颜色,树上跳 (top) 的时候注意合并的处理,(如果现在端的右端点颜色等于上一段左端点颜色,就少计一种颜色),主要是细节问题,感觉还是很锻炼码力的
代码
#include<bits/stdc++.h>
#define ls(pos) pos << 1
#define rs(pos) pos << 1 | 1
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x * f;
}
const int M = 300030;
const int N = 300030;
struct node{
int nxt, to;
}edge[M << 1];
int head[N], num;
void build(int from, int to){
edge[++num].nxt = head[from];
edge[num].to = to;
head[from] = num;
}
namespace Seg{
struct node2{
int sum, cl, cr;
};
int d[N], fa[N], sz[N], son[N], top[N], seg[N], rev[N], val[N], cnt;
void dfs(int u, int f){
d[u] = d[f] + 1; sz[u] = 1; fa[u] = f;
for(int i=head[u]; i; i=edge[i].nxt){
int v = edge[i].to;
if(v == f) continue;
dfs(v, u);
sz[u] += sz[v];
if(sz[son[u]] < sz[v]) son[u] = v;
}
}
void dfs2(int u, int topf){
top[u] = topf; seg[u] = ++ cnt; rev[cnt] = u;
if(!son[u]) return;
dfs2(son[u], topf);
for(int i=head[u]; i; i=edge[i].nxt){
int v = edge[i].to;
if(!seg[v]) dfs2(v, v);
}
}
int S[N << 2], l[N << 2], r[N << 2], C[N << 2];
void pushup(int pos){
l[pos] = l[ls(pos)]; r[pos] = r[rs(pos)];
if(r[ls(pos)] == l[rs(pos)]){
S[pos] = S[ls(pos)] + S[rs(pos)] - 1;
}
else S[pos] = S[ls(pos)] + S[rs(pos)];
}
void builds(int pos, int ll, int rr){
C[pos] = -1;
if(ll == rr) {
S[pos] = 1; l[pos] = r[pos] = val[rev[ll]];
return;
}
int mid = (ll + rr) >> 1;
builds(ls(pos), ll, mid);
builds(rs(pos), mid+1, rr);
pushup(pos);
}
void change(int pos, int v){
S[pos] = 1; C[pos] = v; l[pos] = r[pos] = v;
}
void pushdown(int pos){
if(C[pos] != -1){
change(ls(pos), C[pos]);
change(rs(pos), C[pos]);
C[pos] = -1;
}
}
void modify(int pos, int l, int r, int x, int y, int v){
if(l > y || r < x) return;
if(x <= l && r <= y) return change(pos, v);
pushdown(pos);
int mid = (l + r) >> 1;
if(x <= mid) modify(ls(pos), l, mid, x, y, v);
if(y > mid) modify(rs(pos), mid+1, r, x, y, v);
pushup(pos);
}
node2 query(int pos, int ll, int rr, int x, int y){
if(x <= ll && rr <= y) {
node2 ans = (node2){S[pos], l[pos], r[pos]};
return ans;
}
pushdown(pos);
int mid = (ll + rr) >> 1;
if(y <= mid) return query(ls(pos), ll, mid, x, y);
else if(x > mid) return query(rs(pos), mid+1, rr, x, y);
else{
node2 L = query(ls(pos), ll, mid, x, y);
node2 R = query(rs(pos), mid+1, rr, x, y);
node2 ans;
ans.cl = L.cl; ans.cr = R.cr;
if(R.cl == L.cr){
ans.sum = L.sum + R.sum - 1;
}
else ans.sum = L.sum + R.sum;
return ans;
}
}
void Tmodify(int u, int v, int w){
while(top[u] != top[v]){
if(d[top[u]] < d[top[v]]) swap(u, v);
modify(1, 1, cnt, seg[top[u]], seg[u], w);
u = fa[top[u]];
}
if(d[u] > d[v]) swap(u, v);
modify(1, 1, cnt, seg[u], seg[v], w);
}
int Tquery(int u, int v){
int lal = -1, lar = -1, ans = 0;
while(top[u] != top[v]){
if(d[top[u]] < d[top[v]]) swap(u, v), swap(lal, lar);
node2 ans1 = query(1, 1, cnt, seg[top[u]], seg[u]);
ans += ans1.sum;
if(lal == ans1.cr) ans --; lal = ans1.cl;
u = fa[top[u]];
}
if(d[u] > d[v]) swap(u, v), swap(lal, lar);
node2 ans1 = query(1, 1, cnt, seg[u], seg[v]);
ans += ans1.sum;
if(lal == ans1.cl) ans --;
if(lar == ans1.cr) ans --;
return ans;
}
}
using namespace Seg;
int n, m;
int main(){
n = read(); m = read();
for(int i=1; i<=n; i++) val[i] = read();
for(int i=1; i<=n-1; i++){
int u = read(), v = read();
build(u, v); build(v, u);
}
dfs(1, 0); dfs2(1, 1); builds(1, 1, cnt);
while(m --){
char op[10]; scanf("%s", op + 1);
if(op[1] == 'C'){
int a = read(), b = read(), c = read();
Tmodify(a, b, c);
}
else{
int a = read(), b = read();
printf("%d
", Tquery(a, b));
}
}
return 0;
}
总结
比较码农的题,注意细节就 (ok) ~