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,表示xy之间有一条无向边。

下面 行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

 

Output

对于每个询问操作,输出一行答案。

 

 

题解: 这个题就是树链剖分+线段树的问题,主要是线段树的合并的问题。

 

#include<stdio.h>
#include<string.h>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=2e6+4;
int n,w,_max,_sum;
int flag,Rmost,Lmost;
int sumv[N],maxv[N];
int rank[N],tid[N],top[N],dp[N],fa[N],a[N],siz[N],son[N];
int tot;
int head[N];
int c;
int L[N],R[N];
int setv[N];
int tim;
struct node
{
    int u,v,next;
}edge[N];
void inist()
{
    memset(head,-1,sizeof(head));
    for(int i=1;i<N;i++) setv[i]=-1;
}
void addedge(int u,int v)
{
    edge[tot].u=u; edge[tot].v=v;
    edge[tot].next=head[u]; head[u]=tot++;
}
void build(int o,int l,int r)
{
    if(l==r)
    {
        sumv[o]=1;
        L[o]=a[rank[l]];  R[o]=a[rank[l]];
        return;
    }
    int mid=(r+l)/2;
    build(o*2,l,mid);
    build(o*2+1,mid+1,r);
    if(R[o*2]!=L[o*2+1])
    sumv[o]=sumv[o*2]+sumv[o*2+1];
    else sumv[o]=sumv[o*2]+sumv[o*2+1]-1;
    L[o]=L[o*2];
    R[o]=R[o*2+1];
}
void maintain(int o,int l,int r)
{
    int lc=o*2,rc=o*2+1;
    if(R[lc]!=L[rc]) sumv[o]=sumv[lc]+sumv[rc];
    else sumv[o]=sumv[lc]+sumv[rc]-1;
    L[o]=L[o*2];
    R[o]=R[o*2+1];
}
void query(int o,int l,int r,int ql,int qr)
{
    if(setv[o]!=-1)
    {
        if(flag==0) Lmost=setv[o],_sum+=1,Rmost=setv[o],flag=1;
        else
        {
            if(Rmost!=setv[o]) _sum=_sum+1;
            Rmost=setv[o];
        }
    }
    else if(ql<=l&&qr>=r)
    {
        if(flag==0)
        {
            Lmost=L[o];
            _sum+=sumv[o];
            Rmost=R[o];
            flag=1;
        }
        else
        {
            if(Rmost!=L[o]) _sum=_sum+sumv[o];
            else _sum+=sumv[o]-1;
            Rmost=R[o];
        }
    }
    else
    {
        int mid=(r+l)/2;
        if(ql<=mid) query(o*2,l,mid,ql,qr);
        if(qr>mid) query(o*2+1,mid+1,r,ql,qr);
    }
}
void Puttage(int o,int l,int r)
{
    int lc=o*2,rc=o*2+1;
    if(setv[o]!=-1)
    {
        setv[rc]=setv[lc]=setv[o];
        sumv[lc]=1; L[lc]=setv[lc]; R[lc]=setv[lc];
        sumv[rc]=1; L[rc]=setv[rc]; R[rc]=setv[rc];
        setv[o]=-1;
    }
}
void change(int o,int l,int r,int ql,int qr)
{
    if(ql>r||qr<l) return;
    if(ql<=l&&qr>=r)
    {
        setv[o]=c;
        sumv[o]=1; L[o]=c;  R[o]=c;
        return;
    }
    Puttage(o,l,r);
    int mid=(r+l)>>1;
    change(o*2,l,mid,ql,qr);
    change(o*2+1,mid+1,r,ql,qr);
    maintain(o,l,r);
}
void dfs1(int u,int father,int d)
{
    dp[u]=d;
    fa[u]=father;
    siz[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int y=edge[i].v;
        if(y!=father)
        {
            dfs1(y,u,d+1);
            siz[u]+=siz[y];
            if(son[u]==0||siz[y]>siz[son[u]])
            {
                son[u]=y;
            }
        }
    }
}
void dfs2(int u,int tp)
{
    top[u]=tp;
    tid[u]=++tim;
    rank[tid[u]]=u;
    if(son[u]==0) return;
    dfs2(son[u],tp);
 
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int y=edge[i].v;
        if(y!=son[u]&&y!=fa[u])
        {
            dfs2(y,y);
        }
    }
}
void ANS(int u,int v)
{
    int L_now_1,R_now_1,L_now_2,R_now_2;
    int sum1=0,sum2=0;
    int flag1=0,flag2=0;
    int f1=top[u],f2=top[v];
    while(top[u]!=top[v])
    {
        if(dp[top[u]]>dp[top[v]])
        {
            if(flag1==0)
            {
                flag=0;
                _sum=0;
                query(1,1,n,tid[top[u]],tid[u]);
                sum1+=_sum;
                L_now_1=Lmost;
                flag1=1;
                u=fa[top[u]];
            }
            else
            {
                flag=0;
                _sum=0;
                query(1,1,n,tid[top[u]],tid[u]);
                R_now_1=Rmost;
                if(L_now_1==R_now_1)
                {
                    sum1=_sum+sum1-1;
                }
 
                else sum1+=_sum;
                L_now_1=Lmost;
                u=fa[top[u]];
            }
        }
        else
        {
            if(flag2==0)
            {
                flag=0;
                _sum=0;
                query(1,1,n,tid[top[v]],tid[v]);
                sum2+=_sum;
                L_now_2=Lmost;
                flag2=1;
                v=fa[top[v]];
            }
            else
            {
                flag=0;
                _sum=0;
                query(1,1,n,tid[top[v]],tid[v]);
                R_now_2=Rmost;
                if(L_now_2==R_now_2)
                {
                    sum2+=_sum-1;
                }
 
                else sum2+=_sum;
                 L_now_2=Lmost;
                v=fa[top[v]];
            }
        }
    }
    int temp=0;
    flag=0;
    _sum=0;
    query(1,1,n,min(tid[u],tid[v]),max(tid[u],tid[v]));
    if(tid[u]>tid[v])
    {
        if(flag1&&L_now_1==Rmost)
        {
            temp++;
        }
        if(flag2&&L_now_2==Lmost) temp++;
    }
    else
    {
        if(flag1&&L_now_1==Lmost)
        {
            temp++;
        }
        if(flag2&&L_now_2==Rmost) temp++;
    }
    printf("%d
",sum1+sum2+_sum-temp);
}
void Chan(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(dp[top[u]]<dp[top[v]])
        {
            swap(u,v);
        }
        change(1,1,n,tid[top[u]],tid[u]);
        u=fa[top[u]];
    }
    if(tid[u]>tid[v]) swap(u,v);
    change(1,1,n,tid[u],tid[v]);
}
int main()
{
    int q;
    cin>>n>>q;
    inist();
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        addedge(a,b);
        addedge(b,a);
    }
    dfs1(1,1,1);
    dfs2(1,1);
    build(1,1,n);
    scanf("%d",&q);
    while(q--)
    {
        int u,v;
        char str[10];
        scanf("%s",str);
        if(str[0]=='C')
        {
            int a,b;
            scanf("%d%d%d",&a,&b,&c);
            Chan(a,b);
        }
        else if(str[0]=='Q')
        {
            scanf("%d%d",&u,&v);
            ANS(u,v);
        }
    }
}

 

  

 

原文地址:https://www.cnblogs.com/Heilce/p/7246132.html