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,tmp,top,w;
struct edge{
	edge* s;
	int v;
}e[N<<1],*back=e,*h[N];
void add(int u,int v){
	h[u]=&(*back++=(edge){h[u],v});
	h[v]=&(*back++=(edge){h[v],u});
}
void dfs1(int u){
	size[u]=1;
	dp[u]=dp[p[u]]+1;
	int s=0;
	for(edge* i=h[u];i;i=i->s)
		if(i->v!=p[u]){
			p[i->v]=u;
			dfs1(i->v);
			size[u]+=size[i->v];
			if(s<size[i->v])
				s=size[son[u]=i->v];
		}
}
void dfs2(int u){
	static int cnt;
	tmp[num[u]=++cnt]=w[u];
	if(size[u]!=1){
		top[son[u]]=top[u];
		dfs2(son[u]);
	}
	for(edge* i=h[u];i;i=i->s)
		if(i->v!=p[u]&&i->v!=son[u])
			dfs2(top[i->v]=i->v);
}
typedef int node[1<<18];
node a,d,u,v;
int n;
void apply(int s,int k){
	a[k]=u[k]=v[k]=s;
	d[k]=1;
}
void devolve(int k){
	if(~a[k]){
		apply(a[k],P);
		apply(a[k],S);
		a[k]=-1;
	}
}
void update(int k){
	u[k]=u[P];
	v[k]=v[S];
	d[k]=d[P]+d[S]-(v[P]==u[S]);
}
void build(Z){
	if(l==r)
		apply(tmp[l],k);
	else{
		a[k]=-1;
		build(L);
		build(R);
		update(k);
	}
}
void A(int d,int s,int t,Z){
	if(s==l&&t==r)
		apply(d,k);
	else{
		devolve(k);
		if(t<=M)
			A(d,s,t,L);
		else if(s>M)
			A(d,s,t,R);
		else{
			A(d,s,M,L);
			A(d,M+1,t,R);
		}
		update(k);
	}
}
int Q(int s,int t,Z){
	if(s==l&&t==r)
		return d[k];
	devolve(k);
	return t<=M?Q(s,t,L)
	:s>M?Q(s,t,R)
	:Q(s,M,L)+Q(M+1,t,R)
	-(v[P]==u[S]);
}
int U(int i,Z){
	if(l==r)
		return a[k];
	devolve(k);
	return i<=M?U(i,L):U(i,R);
}
void color(int d,int s,int t){
	while(top[s]!=top[t]){
		if(dp[top[s]]<dp[top[t]])
			swap(s,t);
		A(d,num[top[s]],num[s]);
		s=p[top[s]];
	}
	if(dp[s]<dp[t])
		swap(s,t);
	A(d,num[t],num[s]);
}
int calc(int s,int t){
	int v=0;
	while(top[s]!=top[t]){
		if(dp[top[s]]<dp[top[t]])
			swap(s,t);
		v+=Q(num[top[s]],num[s])
		-(U(num[top[s]])
		==U(num[p[top[s]]]));
		s=p[top[s]];
	}
	if(dp[s]<dp[t])
		swap(s,t);
	return v+Q(num[t],num[s]);
}
int main(){
	int m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		scanf("%d",w+i);
	for(int i=1;i!=n;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	dfs1(1);
	dfs2(top[1]=1);
	build();
	while(m--){
		char d[2];
		int s,t,v;
		scanf("%s%d%d",d,&s,&t);
		if(*d==‘Q‘)
			printf("%d\n",calc(s,t));
		else{
			scanf("%d",&v);
			color(v,s,t);
		}
	}
}
时间: 2024-10-12 00:40:12

bzoj2243: [SDOI2011]染色 树链剖分的相关文章

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

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

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."222"和"1". 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n

bzoj-2243 2243: [SDOI2011]染色(树链剖分)

题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6267  Solved: 2291 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. Input 第一行包含

2243: [SDOI2011]染色(树链剖分+线段树)

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 8400  Solved: 3150[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写

[bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]

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

luogu题解P2486[SDOI2011]染色--树链剖分+trick

题目链接 https://www.luogu.org/problemnew/show/P2486 分析 看上去又是一道强行把序列上问题搬运到树上的裸题,然而分析之后发现并不然... 首先我们考虑如何在序列上维护信息:从最简单的想起,如果两个相邻的元素合并,显然是这两个元素所含颜色段个数(其实就是1)加起来,如果两个元素颜色相同就减1;那么两个分别含有两个元素的相邻区间合并,还是把这两个区间所含颜色段个数加起来,如果左区间最右边的颜色等于右区间最左边的颜色就减去1. 如此我们已经得到线段树维护信息

BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

2243: [SDOI2011]染色 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之间有一条无向边.