SDOI2011 染色
题目大意
给定一棵树,要求支持一条链上的权值修改和查询相同权值的段数(比如 1112211 就是三段)
思路
看到有修改,有树,大概就能直接反应过来是树链剖分了吧(虽然我是专门去找的树链剖分题)
把一段的值都改成某一个值和区间加一样,用一个数组记录一下,在查询的时候再下放就可以了
线段树中需要记录当前区间最左边的颜色、最右边的颜色还有总的颜色数量,build的时候如果左右孩子中间那段颜色相同(比如【1112】和【211】)颜色总数就-1
对于一条链查询的时候当然也会出现类似的问题,可能两条链中间的一段颜色相同,因此可以写一个查询单点颜色的函数,每一次判断一下当前链的链首【top】和这个节点的父亲所染的颜色是否相同,如果相同颜色总数也要-1
其他的就完全和模版一样了。
代码
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; #define lch o<<1 #define rch o<<1|1 #define mid ((l+r)>>1) const int maxn = 100005; int cl[maxn]; int cnt, front[maxn]; int totc[maxn<<2], lc[maxn<<2], rc[maxn<<2], chc[maxn<<2]; int dep[maxn],f[maxn],siz[maxn],hson[maxn],top[maxn]; int tot, id[maxn], real[maxn]; struct Edge { int v,next; }e[maxn*2]; int n,m; void AddEdge(int u,int v) { e[++cnt].v = v; e[cnt].next = front[u]; front[u] = cnt; } void pushup(int o) { totc[o] = totc[rch] + totc[lch]; if(lc[rch] == rc[lch]) totc[o]--; lc[o] = lc[lch]; rc[o] = rc[rch]; } void pushdown(int o) { if(chc[o]) { int x = chc[o]; chc[o] = 0; totc[lch] = totc[rch] = 1; chc[lch] = chc[rch] = lc[lch] = rc[lch] = lc[rch] = rc[rch] = x; } } void build(int o,int l,int r) { if(l == r) { totc[o] = 1; lc[o] = rc[o] = cl[real[l]]; return; } build(lch,l,mid); build(rch,mid+1,r); pushup(o); } void optchan(int o,int l,int r,int ql,int qr, int c) { if(ql <= l && r <= qr) { totc[o] = 1; lc[o] = rc[o] = chc[o] = c; return; } pushdown(o); if(ql <= mid) optchan(lch, l, mid, ql, qr, c); if(qr >= mid+1) optchan(rch, mid+1, r, ql, qr, c); pushup(o); } int querytot(int o,int l,int r,int ql, int qr) { if(ql > r || qr < l) return 0; if(ql <= l && r <= qr) { return totc[o]; } int res = 0; pushdown(o); if(qr <= mid) { querytot(lch,l,mid,ql,qr); } else if(ql >= mid+1) { querytot(rch,mid+1,r,ql,qr); } else { res = querytot(lch,l,mid,ql,qr) + querytot(rch,mid+1,r,ql,qr); if(rc[lch] == lc[rch]) res--; return res; } } int querycol(int o,int l,int r,int x) { if(l == r) { return lc[o]; } pushdown(o); if(x <= mid) querycol(lch,l,mid,x); else querycol(rch,mid+1,r,x); } void dfs1(int u) { dep[u] = dep[f[u]]+1; siz[u] = 1; for (int i = front[u]; i; i = e[i].next) { if(e[i].v != f[u]) { f[e[i].v] = u; dfs1(e[i].v); siz[u] += siz[e[i].v]; if(siz[e[i].v] > siz[hson[u]] || hson[u] == 0) { hson[u] = e[i].v; } } } } void dfs2(int u) { if(!top[u]) top[u] = u; id[u] = ++tot; real[tot] = u; if(hson[u]) { top[hson[u]] = top[u]; dfs2(hson[u]); } for (int i = front[u]; i; i = e[i].next) { if(e[i].v != hson[u] && e[i].v != f[u]) { dfs2(e[i].v); } } } void rcolor() { int a,b,c; scanf("%d%d%d",&a,&b,&c); while(top[a] != top[b]) { if(dep[top[a]] < dep[top[b]]) { swap(a,b); } optchan(1,1,n,id[top[a]],id[a],c); a = f[top[a]]; } if(dep[a] < dep[b]) { swap(a,b); } optchan(1,1,n,id[b],id[a],c); } void rquery() { int a,b; scanf("%d%d",&a,&b); int res = 0; int c1,c2; while(top[a] != top[b]) { if(dep[top[a]] < dep[top[b]]) { swap(a,b); } res += querytot(1,1,n,id[top[a]],id[a]); c1 = querycol(1,1,n,id[top[a]]); c2 = querycol(1,1,n,id[f[top[a]]]); // cout<<c1<<" "<<c2<<endl; if(c1 == c2) res--; a = f[top[a]]; } if(dep[a] < dep[b]) { swap(a,b); } res += querytot(1,1,n,id[b],id[a]); if(!res) res = 1; printf("%d\n",res); } int main() { scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) { scanf("%d",&cl[i]); } for (int i = 1; i < n; i++) { int x,y; scanf("%d%d",&x,&y); AddEdge(x,y); AddEdge(y,x); } dfs1(1); dfs2(1); build(1,1,n); for (int i = 1; i <= m; i++) { char op; cin>>op; if(op == 'C') rcolor(); else rquery(); } return 0; }

浙公网安备 33010602011771号