19暑假树链剖分B

给定一棵有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 b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。

Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
Hint
数N<=105,操作数M<=105,所有的颜色C为整数且在[0, 10^9]之间。
线段树记录左端点和右端点颜色与区间中段数
区间修改和区间访问

#include<stdio.h>
#include<vector>
#define N 100005
using namespace std;
int T[N<<2],lc[N<<2],rc[N<<2],cha[N<<2];
int siz[N],son[N],fa[N],h[N],top[N],pos[N],a[N],val[N];
vector<int> g[N];
int cnt,n,Rc,Lc;
void dfs1(int u,int f)
{
	int i,v;
	siz[u]=1;                
	son[u]=0;                    
	fa[u]=f;                   
	h[u]=h[f]+1;                 
	for(i=0;i<g[u].size();i++)         
	{
		v=g[u][i];
		if(f!=v)
		{
			dfs1(v,u);
			siz[u]+=siz[v];
			if(siz[son[u]]<siz[v])
			son[u]=v;
		}
	}
}
void dfs2(int u,int f,int k)
{
	int i,v;
	top[u]=k;              
	pos[u]=++cnt;            
	a[cnt]=val[u];          
	if(son[u])                  
	dfs2(son[u],u,k);
	for(i=0;i<g[u].size();i++)
	{
		v=g[u][i];
		if(v!=f&&v!=son[u])
		dfs2(v,u,v);
	}
}
void pushup(int k)
{
	lc[k]=lc[k<<1];
	rc[k]=rc[k<<1|1];
	if(rc[k<<1]==lc[k<<1|1])
	T[k]=T[k<<1]+T[k<<1|1]-1;
	else
	T[k]=T[k<<1]+T[k<<1|1];
}
void build(int k,int l,int r)
{
	cha[k]=-1;
	if(l==r)
	{
		lc[k]=rc[k]=a[l];
		T[k]=1;
		cha[k]=-1;
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}
void pushdown(int k)
{
	if(cha[k]>=0)
	{
		cha[k<<1]=cha[k<<1|1]=cha[k];
		rc[k<<1]=lc[k<<1]=cha[k];
		T[k<<1]=1;
		rc[k<<1|1]=lc[k<<1|1]=cha[k];
		T[k<<1|1]=1;
		cha[k]=-1;
	}
}
void change(int k,int l,int r,int L,int R,int c)
{
	if(L<=l&&r<=R)
	{
		T[k]=1;
		cha[k]=c;
		rc[k]=lc[k]=c;
	}
	pushdown(k);
	int mid=(l+r)>>1;
	if(R<=mid)
	change(k<<1,l,mid,L,R,c);
	else if(L>mid)
	change(k<<1|1,mid+1,r,L,R,c);
	else
	{
		change(k<<1,l,mid,L,R,c);
		change(k<<1|1,mid+1,r,L,R,c);
	}
	pushup(k);
}
int qsum(int k,int l,int r,int L,int R)
{
	if(l==L)
        Lc=lc[k];
    if(r==R)
        Rc=rc[k];
    if(L<=l&&r<=R) 
	return T[k];
	pushdown(k);
    int mid=(l+r)>>1;
    if(R<=mid) 
	return qsum(k<<1,l,mid,L,R);
    if(L>mid) 
	return qsum(k<<1|1,mid+1,r,L,R);
	if(rc[k<<1]==lc[k<<1|1])
    return qsum(k<<1,l,mid,L,R)+qsum(k<<1|1,mid+1,r,L,R)-1;
    else 
    return qsum(k<<1,l,mid,L,R)+qsum(k<<1|1,mid+1,r,L,R);
}
int fsum(int u,int v)
{
    int ans=0,ans1=-1,ans2=-1; 
    while(top[u]!=top[v])
	{
        if(h[top[u]]<h[top[v]])
		swap(u,v),swap(ans1,ans2);
        ans+=qsum(1,pos[top[u]],pos[u],pos[top[u]],pos[u]);
        if(Rc==ans1)
		ans--;
        ans1=Lc;
		u=fa[top[u]];
    }
    if(h[u]<h[v])swap(u,v),swap(ans1,ans2);
    ans+=qsum(1,pos[v],pos[u],pos[v],pos[u]);
    if(Rc==ans1)ans--;
    if(Lc==ans2)ans--;
    return ans;
}
int main()
{
	int n,m;
	cnt=0;
	h[0]=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",val+i);
	int u,v,w;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs1(1,0);
	dfs2(1,0,1);
	build(1,1,n);
	char op[5];
	while(m--)
	{

		scanf("%s",op);
		if(op[0]=='Q')
		{		
			scanf("%d%d",&u,&v);
			printf("%d\n",fsum(u,v));
		}
		else
		{
			scanf("%d%d%d",&u,&v,&w);
			change(1,1,n,u,v,w);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值