洛谷P2486染色

题目大意

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

程序如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define MAX (150000+5)
using namespace std;
struct node
{
    int down;
    int sum;
    int l,r;
}Segt[MAX*4];
struct node1
{
    int to;
    int next;
}edge[MAX*2];
int Father[MAX],Depth[MAX];
int Sum[MAX],Son[MAX],Top[MAX];
int TREE[MAX],T_NUM[MAX];
int num_edge,head[MAX],n,cnt;
int a[MAX];

inline int get()
{
    char c;
    int x=0,f=1;
    c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*f;
}

void add(int u,int v)
{
    edge[++num_edge].to=v;
    edge[num_edge].next=head[u];
    head[u]=num_edge;
}

void Build(int node,int l,int r)
{
    if (l==r)
    {
        Segt[node].sum=1;
        Segt[node].l=Segt[node].r=TREE[l];
    }
    else
    {
        int mid=(l+r)/2;
        Build(node*2,l,mid);
        Build(node*2+1,mid+1,r);
        Segt[node].l=Segt[node*2].l;
        Segt[node].r=Segt[node*2+1].r;
        Segt[node].sum=Segt[node*2].sum+Segt[node*2+1].sum-(Segt[node*2].r==Segt[node*2+1].l);
    }
}

void Pushdown(int node)
{
    if (Segt[node].down!=0)
    {
        Segt[node*2].sum=1;
        Segt[node*2+1].sum=1;
        
        Segt[node*2].down=Segt[node].down;
        Segt[node*2+1].down=Segt[node].down;
        
        Segt[node*2].l=Segt[node*2].r=Segt[node].down;
        Segt[node*2+1].l=Segt[node*2+1].r=Segt[node].down;
        
        Segt[node].down=0;
    }
}

int Query(int node,int l,int r,int l1,int r1)
{
    if (r<l1 || l>r1)
        return 0;
    if (l1<=l && r<=r1)
        return Segt[node].sum;
    Pushdown(node);
    int mid=(l+r)/2;
    int x=Query(node*2,l,mid,l1,r1);
    int y=Query(node*2+1,mid+1,r,l1,r1);
    if (x!=0 && y!=0)
        return x+y-(Segt[node*2].r==Segt[node*2+1].l);
    return max(x,y);
}

void Update(int node,int l,int r,int l1,int r1,int k) 
{
    if (r<l1 || l>r1)
        return;
    if (l1<=l && r<=r1)
    {
        Segt[node].down=k;
        Segt[node].sum=1;
        Segt[node].l=Segt[node].r=k;
        return;
    }
    Pushdown(node);
    int mid=(l+r)/2;
    Update(node*2,l,mid,l1,r1,k);
    Update(node*2+1,mid+1,r,l1,r1,k);
    Segt[node].l=Segt[node*2].l;
    Segt[node].r=Segt[node*2+1].r;
    Segt[node].sum=Segt[node*2].sum+Segt[node*2+1].sum-(Segt[node*2].r==Segt[node*2+1].l);
}

int Ask(int node,int l,int r,int x)
{
	if (l==r)
		return Segt[node].l;
	else
	{
		Pushdown(node);
		int mid=(l+r)/2;
		if (x<=mid)	return Ask(node*2,l,mid,x);
		else return Ask(node*2+1,mid+1,r,x);
	}
}

int Get(int x,int y)
{
    int fx=Top[x],fy=Top[y];
    int Ans=0;
    while (fx!=fy)
    {
        if (Depth[fx]<Depth[fy])
            swap(fx,fy),swap(x,y);
        int re=Ask(1,1,n,T_NUM[fx]);
        int fun=Ask(1,1,n,T_NUM[Father[fx]]);
        Ans+=Query(1,1,n,T_NUM[fx],T_NUM[x])-(re==fun);
        x=Father[fx],fx=Top[x];
    }
    if (Depth[x]<Depth[y])
        swap(x,y);
    return Ans+=Query(1,1,n,T_NUM[y],T_NUM[x]);
}

void Change(int x,int y,int k)
{
    int fx=Top[x],fy=Top[y];
    while (fx!=fy)
    {
        if (Depth[fx]<Depth[fy])
            swap(fx,fy),swap(x,y);
        Update(1,1,n,T_NUM[fx],T_NUM[x],k);
        x=Father[fx],fx=Top[x];
    }
    if (Depth[x]<Depth[y])
        swap(x,y);
    Update(1,1,n,T_NUM[y],T_NUM[x],k);
}

void Dfs1(int x)
{
    Depth[x]=Depth[Father[x]]+1;
    Sum[x]=1;
    for (int i=head[x];i!=0;i=edge[i].next)
        if (edge[i].to!=Father[x])
        {
            Father[edge[i].to]=x;
            Dfs1(edge[i].to);
            Sum[x]+=Sum[edge[i].to];
            if (Son[x]==0 || Sum[Son[x]]<Sum[edge[i].to])
                Son[x]=edge[i].to;
        }
}

void Dfs2(int x,int pre)
{
    TREE[++cnt]=a[x];
    T_NUM[x]=cnt;
    Top[x]=pre;
    if (Son[x]!=0)
        Dfs2(Son[x],pre);
    for (int i=head[x];i!=0;i=edge[i].next)
        if (edge[i].to!=Son[x] && edge[i].to!=Father[x])
            Dfs2(edge[i].to,edge[i].to);
}

int main()
{
    char ch;
    int x,y,k,m,u,v;
    n=get();
    m=get();
    for (int i=1;i<=n;++i)
        a[i]=get();
    for (int i=1;i<=n-1;++i)
    {
        u=get();
        v=get();
        add(u,v);
        add(v,u);
    }
    Dfs1(1);
    Father[1]=1;
    Dfs2(1,1);
    Build(1,1,n);
    for (int i=1;i<=m;++i)
    {
        ch=getchar();
        while (ch!='C'&&ch!='Q') ch=getchar();
        if (ch=='Q')
            x=get(),y=get(),printf("%d\n",Get(x,y));
        else
            x=get(),y=get(),k=get(),Change(x,y,k);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值