洛谷 P2486 BZOJ 2243 [SDOI2011]染色

简介: 题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1、将节点a到节点b路径上所有点都染成颜色c; 2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

题目描述

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

1、将节点a到节点b路径上所有点都染成颜色c;

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

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

输入输出格式

输入格式:

第一行包含2个整数n和m,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面 行每行包含两个整数x和y,表示xy之间有一条无向边。

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

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

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

输出格式:

 

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

 

输入输出样例

输入样例#1:
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
输出样例#1:
3
1
2

说明

//这个题面一半来自洛谷,一半来自BZOJ

解题思路

  树剖套线段树。这题重点在线段树上。线段树的每个节点存下此节点表示的区间范围l、r,这个区间内颜色块数num,l处的颜色lc,r处的颜色rc。

  然后从合并两个区间的信息时,特判如果接口处颜色相同,则当前区间num等于两个子区间num之和减一,不相等就不减一(语文不好,勉强看吧)

源代码

#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>

int n,m;

struct Edge{
    int next,to;
}e[200010];
int head[100010]={0},cnt=1;
void add(int u,int v)
{
    e[cnt]={head[u],v};
    head[u]=cnt++;
}
int color[100010]={0};
struct tree{
    int fa;
    int w;
    int dep;
    int num_to;
    int wson;
    int top;
    int id;
}t[100010];

void dfs1(int fa,int u,int dep)
{
    t[u].fa=fa;
    t[u].dep=dep;
    t[u].num_to=1;
    t[u].wson=-1;
    int max_to=0,num_son=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa) continue;
        num_son++;
        dfs1(u,v,dep+1);
        int temp=t[v].num_to;
        t[u].num_to+=temp;
        if(temp>max_to) t[u].wson=v,max_to=temp;
    }
}
int id=1;
void dfs2(int u,int top)
{
    t[u].top=top;
    t[u].id=id;
    color[id]=t[u].w;
    id++;
    if(t[u].wson==-1) return;
    dfs2(t[u].wson,top);
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==t[u].fa||v==t[u].wson) continue;
        dfs2(v,v);
    }
}

struct stree{
    int l,r;
    int lc,rc;//边界l、r的颜色
    int num;//区间内色块数
}s[400010];
int lazy[400010]={0};//区间染色lazy
void maketree(int x,int l,int r)
{
    s[x].l=l,s[x].r=r;
    s[x].lc=color[l],s[x].rc=color[r];
    if(l==r)
    {
        s[x].num=1;
        return;
    }
    int mid=l+r>>1;
    maketree(x<<1,l,mid);
    maketree(x<<1|1,mid+1,r);
    s[x].num=s[x<<1].num+s[x<<1|1].num-(s[x<<1].rc==s[x<<1|1].lc);
}
void pushdown(int x)
{
    int ls=x<<1,rs=ls|1;
    s[rs].num=s[ls].num=1;
    s[ls].lc=s[ls].rc=s[rs].rc=s[rs].lc=lazy[ls]=lazy[rs]=lazy[x];
    lazy[x]=0;
}
int query(int x,int l,int r)
{
    if(l>s[x].r||r<s[x].l) return 0;
    if(l<=s[x].l&&s[x].r<=r) return s[x].num;
    if(lazy[x]) pushdown(x);
    int ans=query(x<<1,l,r)+query(x<<1|1,l,r);
    if(l<=s[x<<1].r&&r>=s[x<<1|1].l&&s[x<<1].rc==s[x<<1|1].lc) ans--;
    return ans;
}
int query_color(int x,int pos)
{
    int l=s[x].l,r=s[x].r;
    if(l==r) return s[x].lc;
    int mid=l+r>>1;
    if(lazy[x]) pushdown(x);
    if(pos<=mid) return query_color(x<<1,pos);
    else return query_color(x<<1|1,pos);
}
void update(int x,int l,int r,int c)
{
    if(l>s[x].r||r<s[x].l) return;
    if(l<=s[x].l&&s[x].r<=r)
    {
        lazy[x]=c;
        s[x].num=1;
        s[x].lc=s[x].rc=c;
        return;
    }
    if(lazy[x]) pushdown(x);
    update(x<<1,l,r,c),update(x<<1|1,l,r,c);
    s[x].lc=s[x<<1].lc;
    s[x].rc=s[x<<1|1].rc;
    s[x].num=s[x<<1].num+s[x<<1|1].num-(s[x<<1].rc==s[x<<1|1].lc);
}

void C(int x,int y,int c)
{
    while(t[x].top!=t[y].top)
    {
        if(t[t[y].top].dep<t[t[x].top].dep) std::swap(x,y);//y的top更深
        update(1,t[t[y].top].id,t[y].id,c);
        y=t[t[y].top].fa;
    }
    if(t[y].id<t[x].id) std::swap(x,y);
    update(1,t[x].id,t[y].id,c);
}
int Q(int x,int y)
{
    int ans=0;
    while(t[x].top!=t[y].top)
    {
        if(t[t[y].top].dep>t[t[x].top].dep) std::swap(x,y);//x的top更深
        ans+=query(1,t[t[x].top].id,t[x].id)-(query_color(1,t[t[x].top].id)==query_color(1,t[t[t[x].top].fa].id));
        x=t[t[x].top].fa;
    }
    if(t[y].id<t[x].id) std::swap(x,y);
    ans+=query(1,t[x].id,t[y].id);
    return ans==0?1:ans;
}

int main()
{
    //freopen("test.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&t[i].w);
    for(int i=1,u,v;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(0,1,1);
    dfs2(1,1);
    maketree(1,1,n);
    for(int i=1,a,b,c;i<=m;i++)
    {
        char mode[2];
        scanf("%s",mode);
        if(mode[0]=='Q')
        {
            scanf("%d%d",&a,&b);
            printf("%d\n",Q(a,b));
        }
        else
        {
            scanf("%d%d%d",&a,&b,&c);
            C(a,b,c);
        }
    }
    return 0;
}

 

目录
相关文章
BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】
1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 23822  Solved: 6012[Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊...
924 0
洛谷 2634&&BZOJ 2152: 聪聪可可【点分治学习+超详细注释】
2152: 聪聪可可 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 3435  Solved: 1776[Submit][Status][Discuss] Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。
1460 0
BZOJ 1041: [HAOI2008]圆上的整点【数论,解方程】
1041: [HAOI2008]圆上的整点 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4210  Solved: 1908[Submit][Status][Discuss] Description 求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。
1294 0
|
人工智能 BI
洛谷 P3183 BZOJ 4562 [HAOI2016]食物链
题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数。物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a3 b3......am-1 bm-1am bm其中ai bi表示能量从物种ai流向物种bi,注意单独的一种孤立生物不算一条食物链 输入输出格式 输入格式:   第一行两个整数n和m,接下来m行每行两个整数ai bi描述m条能量流动关系。
1052 0
|
算法
BZOJ 1083: [SCOI2005]繁忙的都市【Kruscal最小生成树裸题】
1083: [SCOI2005]繁忙的都市 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2925  Solved: 1927[Submit][Status][Discuss] Description   城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造。
1156 0
|
机器学习/深度学习
洛谷 P1129 BZOJ 1059 cogs 660 [ZJOI2007]矩阵游戏
题目描述 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏。矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作: 行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色) 列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色) 游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。
959 0
|
人工智能
BZOJ 2257: [Jsoi2009]瓶子和燃料【数论:裴蜀定理】
2257: [Jsoi2009]瓶子和燃料 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1326  Solved: 815[Submit][Status][Discuss] Description jyy就一直想着尽快回地球,可惜他飞船的燃料不够了。
1175 0
洛谷 P2634 BZOJ 2152 【模板】点分治(聪聪可可)
题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。
925 0
|
定位技术
洛谷 P2805 BZOJ 1565 植物大战僵尸
题目描述 Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏。Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻。该款游戏包含多种不同的挑战系列,比如Protect Your Brain、Bowling等等。
932 0
洛谷 P3227 BZOJ 3144 [HNOI2013]切糕
题目描述 经过千辛万苦小 A 得到了一块切糕,切糕的形状是长方体,小 A 打算拦腰将切糕切成两半分给小 B。出于美观考虑,小 A 希望切面能尽量光滑且和谐。于是她找到你,希望你能帮她找出最好的切割方案。
866 0