luogu P2486 [SDOI2011]染色 解题报告

P2486 [SDOI2011]染色

题目分析:
这题看似很诡异,求的不是不同颜色的数量,而是颜色段的数量,可是仔细一想,这不就是个区间合并吗,记录区间的左右端点颜色,当合并的时候,假如左儿子的右端点和右儿子的左儿子相同,总数-1,然后其他部分标准的树链剖分,直接粘了之前的代码,就把线段树的部分重新写了下

反思:查询操作的时候,想复杂了,其实一个flag标记一下当前是否旋转了即可,假如旋转了,就代表线段树查的是反的,合并的时候记得先交换下左右端点颜色即可,一开始写的老复杂了,又是记录端点,又是判断上一条链的顶部。。。。。。
以及线段树部分似乎多写了不少这题根本用不到的操作

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
typedef vector<int> VI;
//const ll mod=1000000007;
const int maxn=2e5+10;
//const int inf=0x3f3f3f3f;
const ll inf = 1e18;
//const int inf=0x7fffffff;
ll gcd(ll a,ll b) {
    return b?gcd(b,a%b):a;
}
//	  freopen("1.txt","r",stdin);
//    freopen("2.txt","w",stdout);
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
//ll mod;
#define int ll
int n,m;
int u,v;
int l,r,z;
//预备工作,处理好边
int val[maxn];
int head[maxn],ed;//ed计数器,cnt要给dfs2用,呜呜呜
struct Edge{
	int to,next;
}edge[maxn<<1];
void addedge(int u,int v)
{
	edge[++ed].to=v;
	edge[ed].next=head[u];
	head[u]=ed;
} 
//dfs1 需要做的事情
//跑出每个点的深度,每个点的父亲,
//每个非叶子的节点的子树大小(这个大小是包括自己的)
//每个非叶子的节点的重儿子 
int depth[maxn];
int father[maxn],size[maxn];
int maxson[maxn],son[maxn];
void dfs1(int now,int fa,int dep)
{//now当前节点 fa 父节点 dep 当前深度
 	depth[now]=dep;
 	father[now]=fa;
 	size[now]=1;//记录非叶子节点的子树大小
	maxson[now]=-1;
	son[now]=-1;
	for(int i = head[now];i;i=edge[i].next)
	{
		int d=edge[i].to;
		if(d==fa)
		continue;
		dfs1(d,now,dep+1);
		size[now]+=size[d];
		if(size[d]>maxson[now])
		{//标记每一个非叶子节点的重儿子 
			maxson[now]=size[d];
			son[now]=d;
		}
	}
}
//dfs2
int cnt;
int id[maxn],newid[maxn];
int top[maxn];//记录当前节点所在重链的首节点 
int newval[maxn];
void dfs2(int now,int first)
{//first 当前重链的首节点
	id[now]=++cnt;//记录当前节点的新编号 
	newval[cnt]=val[now];//按新编号记录节点,并将之前的值赋值给新的编号点
	top[now]=first;//记录当前首节点 
	if(son[now]==-1)//是叶子节点,压根没东西
	{//自己是一条重链,可以回滚了 
		return ;
	}
	else
	{
		dfs2(son[now],first);//优先处理重儿子
		for(int i=head[now];i;i=edge[i].next)
		{
			int d=edge[i].to;
			if(d==son[now] || d==father[now])
			continue;
			//对于非叶子节点,对于每一个轻儿子,都有一个从自己开始的重链 
			dfs2(d,d);
		} 
	}
}
//记录左右区间颜色
//当ls 和 rs合并的时候
//假如ls 的右颜色 和 rs的左颜色相同
// sum= ls.sum + rs.sum-1 
struct Segment_Tree{
	#define ls(p) (p<<1)
	#define rs(p) (p<<1|1)
	struct node{
		int l,r;
		int sum;
		int lcol,rcol;
		int lazy;
		node()
		{
			l=r=sum=lcol=rcol=lazy=0;
		}
		void init(int x=0)
		{
			lcol=rcol=sum=x;
			lazy=0;
		}
		node operator + (const node & b) const
		{
			if(l==r && l==0)
			{
				return b;
			}
			if(b.l==b.r && b.l==0)
			{
				node ans;
				ans.sum=sum;
				ans.l=l;
				ans.r=r;
				ans.lazy=0;
				ans.lcol=lcol;
				ans.rcol=rcol;
				return ans;
			}
			node ans;
			ans.lazy=0;
			ans.sum=sum+b.sum;
			ans.l=l;
			ans.r=b.r;
			ans.lcol=lcol;
			ans.rcol=b.rcol;
			if(rcol==b.lcol)
			{
				ans.sum--;
			}
			return ans;
		}
	}t[maxn<<2];
	void update(int p,int z)
	{
		t[p].lazy=z;
		t[p].sum=1;
		t[p].lcol=z;
		t[p].rcol=z;
	}
	void push_down(int p)
	{
		if(t[p].lazy)
		{
			update(ls(p),t[p].lazy);
			update(rs(p),t[p].lazy);
			t[p].lazy=0;
		}
	}
	void push_up(int p)
	{
		t[p].sum=t[ls(p)].sum+t[rs(p)].sum;
		t[p].lcol=t[ls(p)].lcol;
		t[p].rcol=t[rs(p)].rcol;
		t[p].l=t[ls(p)].l;
		t[p].r=t[rs(p)].r;
		if(t[ls(p)].rcol==t[rs(p)].lcol)
		{
			t[p].sum--;
		}
		t[p].lazy=0;
	}
	void build(int p,int l,int r)
	{
		if(l==r)
		{
			t[p].l=l;
			t[p].r=l;
			t[p].lcol=newval[l];
			t[p].rcol=newval[l];
			t[p].sum=1;
			return ;
		}
		int mid=(l+r)>>1;
		build(ls(p),l,mid);
		build(rs(p),mid+1,r);
		push_up(p);
	}
	void change(int p,int l,int r,int ql,int qr,int x)
	{
		if(ql<=l && r<=qr)
		{
			update(p,x);
			return ;
		}
		push_down(p);
		int mid=(l+r)>>1;
		if(ql<=mid)
		change(ls(p),l,mid,ql,qr,x);
		if(mid<qr)
		change(rs(p),mid+1,r,ql,qr,x);
		push_up(p);
	}
	node query(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l && r<=qr)
		{
			return t[p];
		}
		push_down(p);
		int mid=(l+r)>>1;
		node ans;
		if(ql<=mid && mid<qr)
		{
			ans=query(ls(p),l,mid,ql,qr)+query(rs(p),mid+1,r,ql,qr);
		}
		else
		if(ql<=mid)
		{
			ans=query(ls(p),l,mid,ql,qr);
		}
		else
		{
			ans=query(rs(p),mid+1,r,ql,qr);
		}
		push_up(p);
		return ans;
	}
}S1;
void change(int x,int y,int k)
{
	while(top[x]!=top[y])
	{
//		cout<<x<<" "<<y<<" "<<k<<"\n";
		if(depth[top[x]]<depth[top[y]])
		{
			swap(x,y);
		}
		S1.change(1,1,n,id[top[x]],id[x],k);
		x=father[top[x]];
	}
	if(depth[x]>depth[y])
	swap(x,y);
//	cout<<x<<" "<<y<<" "<<k<<"\n"; 
	S1.change(1,1,n,id[x],id[y],k);
}
int query(int x,int y)
{
	int flag=0;
	Segment_Tree::node ans0,ans1;
	while(top[x]!=top[y])
	{
		if(depth[top[x]]<depth[top[y]])
		{
			swap(x,y);
			flag^=1;
		}
		Segment_Tree::node qwe;
			qwe=S1.query(1,1,n,id[top[x]],id[x]);
		if(flag)
		{//x,y翻转了一次 
			ans1=qwe+ans1; 
		}
		else
		{
			swap(qwe.lcol,qwe.rcol);
			ans0=ans0+qwe;
		}
		x=father[top[x]];
	}
	if(depth[x]>depth[y])
	swap(x,y),flag^=1;
	Segment_Tree::node qwe;
	qwe=S1.query(1,1,n,id[x],id[y]);
	if(flag)
	{
		swap(qwe.lcol,qwe.rcol);
		ans0=ans0+qwe;
	}
	else
	{
		ans1=qwe+ans1;
	}
	ans0=ans0+ans1;
	return ans0.sum;
}
#undef int
int main()
{
//		  freopen("1.txt","r",stdin);
//    freopen("3.txt","w",stdout);
//	iossync;
	cin>>n>>m;
	rep(i,1,n+1)
	cin>>val[i];
	rep(i,1,n)
	{
		cin>>u>>v;
		addedge(u,v);
		addedge(v,u);
	}
	dfs1(1,0,1);
	dfs2(1,1);
	S1.build(1,1,n);
	string qwe;
	while(m--)
	{
		cin>>qwe;
		switch(qwe[0])
		{
			case 'C':{
				cin>>l>>r>>z;
				change(l,r,z);
				break;
			}
			case 'Q':{
				cin>>l>>r;
				cout<<query(l,r)<<"\n";
				break;
			}
		}
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值