BZOJ2243 [SDOI2011]染色

题意:树,路径染色,路径查询分了几段。

分析:

树链剖分套线段树,没写过,代码写得很乱,还犯了不少错,加了点注释,以后不能犯这种错了。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define m ((L+R)>>1)
#define lc o<<1
#define rc o<<1|1
#define ls lc,L,m
#define rs rc,m+1,R
#define init 1,1,n
const int N = 100005; char op[1];
int n,q,e,x,y,z,tt,c[N*4],l[N*4],r[N*4],st[N*4],v[N],hd[N],nxt[N*2],to[N*2],d[N],p[N],tp[N],f[N],s[N],sz[N],pp[N];

void add(int x, int y) {to[++e] = y, nxt[e] = hd[x], hd[x] = e;}
//判断R > L和st!!!!
void pu(int o, int L, int R) {
	if(R > L) c[o] = c[lc] + c[rc] + (r[lc] == l[rc] ? -1 : 0), l[o] = l[lc], r[o] = r[rc];
	if(~st[o]) c[o] = 1, l[o] = r[o] = st[o];
}
void pd(int o) {if(~st[o]) st[lc] = st[rc] = st[o], st[o] = -1;}
void bd(int o, int L, int R) {
	if(L == R) {
		l[o] = r[o] = v[pp[L]], c[o] = 1;	//不要写成v[L]或v[p[L]]
		return;
	}
	bd(ls), bd(rs), pu(o, L, R);
}
int gt(int o, int L, int R, int p) {
	if(~st[o]) return st[o];
	if(L == R) return l[o];
	if(p <= m) return gt(ls, p);
	return gt(rs, p);
}
void up(int o, int L, int R, int l, int r, int p) {
    if(l <= L && r >= R) st[o] = p;
    else {
        pd(o); if(l <= m) up(ls, l, r, p); else pu(ls);
        if(r > m) up(rs, l, r, p); else pu(rs);
    }
    pu(o, L, R);
}
int qry(int o, int L, int R, int ll, int rr) {
	if(~st[o]) return 1;
    if(ll <= L && rr >= R) return c[o];
    if(rr <= m) return qry(ls, ll, rr); if(ll > m) return qry(rs, ll, rr);
    return qry(ls, ll, rr) + qry(rs, ll, rr) + (r[lc] == l[rc] ? -1 : 0);
}

void dfs1(int x) {
	int mx = 0; sz[x] = 1;
	for(int i = hd[x]; i; i = nxt[i]) if(!d[to[i]]) {
		d[to[i]] = d[x] + 1, f[to[i]] = x;
		dfs1(to[i]), sz[x] += sz[to[i]];
		if(sz[to[i]] > mx) mx = sz[to[i]], s[x] = to[i];
	}
}
void dfs2(int x) {
	if(s[x]) tp[s[x]] = tp[x], p[s[x]] = ++tt, pp[tt] = s[x], dfs2(s[x]);
	for(int i = hd[x]; i; i = nxt[i]) if(to[i] != f[x] && to[i] != s[x])
		tp[to[i]] = to[i], p[to[i]] = ++tt, pp[tt] = to[i], dfs2(to[i]);
}
int qr(int x, int y) {
	int ans = 0;
	while(tp[x] != tp[y]) {
		if(d[tp[x]] < d[tp[y]]) swap(x, y);	//深度判断用tp[x]和tp[y]!!!
		ans += qry(init, p[tp[x]], p[x]);
		if(gt(init, p[tp[x]]) == gt(init, p[f[tp[x]]])) ans--;
		x = f[tp[x]];
	}
	if(d[x] < d[y]) swap(x, y);
	ans += qry(init, p[y], p[x]);	//最后用p[y],不能用p[tp[x]]
	return ans;
}
void upd(int x, int y, int z) {
	while(tp[x] != tp[y]) {
		if(d[tp[x]] < d[tp[y]]) swap(x, y);
		up(init, p[tp[x]], p[x], z);
		x = f[tp[x]];
	}
	if(d[x] < d[y]) swap(x, y);
	up(init, p[y], p[x], z);
}

int main() {
	memset(st, -1, sizeof st);
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
	for(int i = 1; i < n; i++) scanf("%d%d", &x, &y), add(x, y), add(y, x);
	d[1] = 1, dfs1(1), tp[1] = 1, p[1] = ++tt, pp[tt] = 1, f[1] = 1, dfs2(1), bd(init); //别忘了初始化某些数组
	while(q--) {
		scanf("%s%d%d", op, &x, &y);
		if(op[0] == 'Q') printf("%d\n", qr(x, y)); else scanf("%d", &z), upd(x, y, z);
	}
	return 0;
}
时间: 2024-10-28 22:58:53

BZOJ2243 [SDOI2011]染色的相关文章

bzoj2243 [SDOI2011]染色 动态树

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 110000 int pre[N],ch[N][2]; int e[N],ne[N*2],v[N*2]; int nn,m; int col[N]; int lc[N],sm[N],rc[N],num[N]; int rt[N],n; int qu[N

[BZOJ2243][SDOI2011]染色 解题报告|树链剖分

Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. 与上一题差别不大,主要就是solve过程要根据左端点和右端点的颜色处理合并时候的情况 线段树的每个节点要记录颜色段数|最左边的颜色|最右边的颜色 同时往下传的时候标记要做好(之前那道题是单点修改所以不用考虑

BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

题目链接 BZOJ2243 树链剖分+线段树合并 线段树合并的一些细节需要注意一下 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 100010; int n, m,

bzoj2243: [SDOI2011]染色 树链剖分

裸树剖. #include<bits/stdc++.h> using namespace std; #define N 100010 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define L l,M,P #define R M+1,r,S #define Z int l=1,int r=n,int k=1 typedef int ds[N]; ds dp,num,p,size,son,t

bzoj2243 sdoi2011 染色 paint

明明是裸树剖 竟然调了这么久好蛋疼 大概是自己比较水的原因吧 顺便+fastio来gangbang #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cstdio> #include<cctype> using namespace std; const int Maxn=100010,Maxm=Maxn; int n,

[BZOJ2243]SDOI2011染色|树链剖分|LCT

裸题嘛.. 先考虑一条线段上如何查询颜色段数,只要对每个线段树节点多维护一个左颜色和右颜色,然后合并的时候sum[x]=sum[lc]+sum[rc]-(左儿子的右颜色==右儿子的左颜色)..实在太久没写树剖结果码+调试花了两节多晚自习,,各种傻逼错误,什么反向边忘加,标记忘记下传...还有就是更新答案的时候,关键的一点是要保证当前的两点(也就是a,b)是没有被更新到的,否则很难搞.. 表示LCT要更好写..不过在BZOJ上我的树链剖分6000+MS,LCT要13000+MS.. 树链剖分: #

【树链剖分】bzoj2243 [SDOI2011]染色

树链剖分模板题.线段树维护每个段中的颜色数.左端点颜色.右端点颜色. pushup: col[rt]=col[rt<<1]+col[rt<<1|1]-(Rcol[rt<<1]==Lcol[rt<<1|1]); 在合并各个链的答案时,要注意若两头颜色相同,ans--. [教训:树链剖分题在进行建立线段树树时,要注意下面代码中的标注部分.否则会WA] Code: 1 #include<cstdio> 2 #include<algorithm&g

bzoj2243: [SDOI2011]染色--线段树+树链剖分

此题代码量较大..但是打起来很爽 原本不用lca做一直wa不知道为什么.. 后来改lca重打了一遍= =结果一遍就AC了orz 题目比较裸,也挺容易打,主要是因为思路可以比较清晰 另:加读入优化比没加快了1.3s.. 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 100010; 6 struct node{

[BZOJ2243][SDOI2011]染色(树链剖分)

[传送门] 树链剖分就行了,注意线段树上颜色的合并 Code #include <cstdio> #include <algorithm> #define N 100010 #define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1 #define len (r-l+1) using namespace std; struct tree{ int lc,rc,sum,tag; tree(){lc=rc=tag