BZOJ 2243 染色 树链剖分

题目大意:给定一棵树,树上的每个点有一个颜色

给定两种操作

Q:询问节点x到节点y路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

C:将节点x到节点y路径上所有点都染成颜色z

首先这种题一看就能反应出来是树链剖分

然后就是线段树的区间合并问题了

每个节点保存区间内的颜色段数、左端点颜色和右端点颜色

两段区间合并时,若左区间右端点和右区间左端点颜色相同,则新区间段数为左右区间之和-1

否则即为两区间之和

询问时也是这种处理方法 不过小心别把左右弄反了

本来很快就写完了 然后读入C和Q的时候忘记了Linux里的回车是'\r' 因为这点P事WA了一下午 拍了三千组数据全过了 交上去第一个点就WA 我勒个去。。。。

总之贴代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ls tree[p].lson
#define rs tree[p].rson
#define M 100100
using namespace std;
struct Col{	int num,lcol,rcol; }empty;
struct Tree{
	Col col,mark;
	int lson,rson;
}tree[M<<1];
struct abcd{
	int to,next;
}table[M<<1];
int head[M],tot=1;
int n,m,fa[M],col[M],son[M],dpt[M],siz[M],pos[M],top[M],poscol[M],cnt;
void add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void dfs1(int x)
{
	int i;
	siz[x]=1;
	dpt[x]=dpt[fa[x]]+1;
	for(i=head[x];i;i=table[i].next)
	{
		if(table[i].to==fa[x])
			continue;
		fa[table[i].to]=x;
		dfs1(table[i].to);
		if(siz[table[i].to]>siz[son[x]])
			son[x]=table[i].to;
		siz[x]+=siz[table[i].to];
	}
}
void dfs2(int x)
{
	int i;
	if(son[fa[x]]==x)
		top[x]=top[fa[x]];
	else
	{
		top[x]=x;
		for(i=x;i;i=son[i])
			pos[i]=++cnt;
	}
	poscol[pos[x]]=col[x];
	for(i=head[x];i;i=table[i].next)
	{
		if(table[i].to==fa[x])
			continue;
		dfs2(table[i].to);
	}
}
Col operator + (Col x,Col y)
{
	Col re;
	re.lcol=x.lcol;
	re.rcol=y.rcol;
	re.num=x.num+y.num-(x.rcol==y.lcol);
	return re;
}
void Build_tree(int p,int x,int y)
{
	int mid=x+y>>1;
	if(x==y)
	{
		tree[p].col.num=1;
		tree[p].col.lcol=tree[p].col.rcol=poscol[mid];
		return ;
	}
	ls=++tot;rs=++tot;
	Build_tree(ls,x,mid);
	Build_tree(rs,mid+1,y);
	tree[p].col=tree[ls].col+tree[rs].col;
}
Col getans(int p,int x,int y,int l,int r)
{
	int mid=x+y>>1;
	if(x==l&&y==r)
		return tree[p].col;
	if(tree[p].mark.num)
	{
		tree[ls].col=tree[rs].col=tree[p].mark;
		tree[ls].mark=tree[rs].mark=tree[p].mark;
		tree[p].mark=empty;
	}
	if(r<=mid)	return getans(ls,x,mid,l,r);
	if(l>mid) return getans(rs,mid+1,y,l,r);
	return getans(ls,x,mid,l,mid) + getans(rs,mid+1,y,mid+1,r);
}
int Q(int x,int y)
{
	Col xcol=empty,ycol=empty;
	int fx=top[x],fy=top[y];
	while(fx!=fy)
	{
		if(dpt[fx]<dpt[fy])
			swap(x,y),swap(fx,fy),swap(xcol,ycol);
		xcol=getans(0,1,n,pos[fx],pos[x])+xcol;
		x=fa[fx];
		fx=top[x];
	}
	if(dpt[x]<dpt[y])
		swap(x,y),swap(fx,fy),swap(xcol,ycol);
	xcol=getans(0,1,n,pos[y],pos[x])+xcol;
	return xcol.num+ycol.num-(xcol.lcol==ycol.lcol);
}
void change(int p,int x,int y,int l,int r,Col z)
{
	int mid=x+y>>1;
	if(x==l&&y==r)
	{
		tree[p].col=z;
		tree[p].mark=z;
		return ;
	}
	if(tree[p].mark.num)
	{
		tree[ls].col=tree[rs].col=tree[p].mark;
		tree[ls].mark=tree[rs].mark=tree[p].mark;
		tree[p].mark=empty;
	}
	if(r<=mid)	change(ls,x,mid,l,r,z);
	else if(l>mid) change(rs,mid+1,y,l,r,z);
	else change(ls,x,mid,l,mid,z) , change(rs,mid+1,y,mid+1,r,z);
	tree[p].col=tree[ls].col+tree[rs].col;
}
void C(int x,int y,int z)
{
	int fx=top[x],fy=top[y];
	Col zmark;
	zmark.num=1;
	zmark.lcol=zmark.rcol=z;
	while(fx!=fy)
	{
		if(dpt[fx]<dpt[fy])
			swap(x,y),swap(fx,fy);
		change(0,1,n,pos[fx],pos[x],zmark);
		x=fa[fx];
		fx=top[x];
	}
	if(dpt[x]<dpt[y])
		swap(x,y),swap(fx,fy);
	change(0,1,n,pos[y],pos[x],zmark);
}
inline char get_char()
{
	char c;
	do c=getchar(); while(c=='\n'||c==' '||c=='\r');
	return c; 
}
int main()
{
	int i,x,y,z;
	char p;
	
	cin>>n>>m;
	for(i=1;i<=n;i++)
		scanf("%d",&col[i]),col[i]++;
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	tot=0;
	dfs1(1);
	dfs2(1);
	Build_tree(0,1,n);
	for(i=1;i<=m;i++)
	{
		p=get_char();
		if(p=='Q')
		{
			scanf("%d%d",&x,&y);
			printf("%d\n",Q(x,y));
		}
		else
		{
			scanf("%d%d%d",&x,&y,&z);
			C(x,y,z+1);
		}
	}
}


你可能感兴趣的:(线段树,树链剖分,bzoj,BZOJ2243)