题目描述 Description

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

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

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

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

输入描述 Input Description

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

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

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

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

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

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

输出描述 Output Description
 对于每个询问操作,输出一行答案。
样例输入 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

数据范围及提示 Data Size & Hint
 对于100%的数据1≤n≤10^5,1≤m≤10^5,1≤c≤10^9;

很明显是一道树链剖分的题,所以我们只需要考虑线性时候该怎么搞了。

用线段树是肯定的。对于每一个节点o,维护该区间内颜色块数量是肯定的,用cnum[o]来表示。但是发现不能强行合并,因为相邻部分有可能颜色相同,算成一块。所以我们再需要维护两个信息L[o]与R[o]分别记录区间o最左端的颜色以及最右边颜色就可以了。在pushup过程中需要判断如果r[lo]==l[ro],cnum[o]--;这样的话线性做法就可以了。

写好线段树之后,默一份树链剖分代码上去,套一个线段树,结果发现连样例都过不了!手画一下样例,发现在树链上进行操作时进行了若干次query,这些query中的相邻部分有可能颜色相同,怎么办呢,不要慌,我们再写一个名叫special的函数,专门来计算每一条重链上最上段点的颜色,在合并的时候特判一下就好了。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
inline int read()
{
int x=,f=;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-;c=getchar();}
while(isdigit(c)){x=x*+c-'';c=getchar();}
return x*f;
}
const int maxn=;
int n,m,ce=-,es,a,b,c,first[maxn],size[maxn],fa[maxn],deep[maxn],w[maxn],id[maxn],bl[maxn];
char tp;
int cnum[maxn<<],L[maxn<<],R[maxn<<],tag[maxn<<],col[maxn];
struct Edge
{
int u,v,next;
Edge() {}
Edge(int _1,int _2,int _3) : u(_1),v(_2),next(_3) {}
}e[maxn<<];
void addEdge(int a,int b)
{
e[++ce]=Edge(a,b,first[a]);first[a]=ce;
e[++ce]=Edge(b,a,first[b]);first[b]=ce;
}
void dfs(int now,int pa)
{
size[now]=;
for(int i=first[now];i!=-;i=e[i].next)
if(e[i].v!=pa)
{
fa[e[i].v]=now;deep[e[i].v]=deep[now]+;
dfs(e[i].v,now);
size[now]+=size[e[i].v];
}
}
void divide(int now,int chain)
{
id[now]=++es;bl[now]=chain;
int maxs=;
for(int i=first[now];i!=-;i=e[i].next)
if(fa[now]!=e[i].v && size[e[i].v]>size[maxs])maxs=e[i].v;
if(!maxs)return;
divide(maxs,chain);
for(int i=first[now];i!=-;i=e[i].next)
if(fa[now]!=e[i].v && e[i].v!=maxs)divide(e[i].v,e[i].v);
}
void pushdown(int l,int r,int o)
{
if(tag[o]==- || l==r)return;
int mid=(l+r)>>,lo=o<<,ro=lo|;
tag[lo]=tag[ro]=tag[o];
cnum[lo]=cnum[ro]=;
L[lo]=R[lo]=L[ro]=R[ro]=L[o];
tag[o]=-;
}
void pushup(int l,int r,int o)
{
int mid=(l+r)>>,lo=o<<,ro=lo|;
L[o]=L[lo];R[o]=R[ro];
cnum[o]=cnum[lo]+cnum[ro];
if(R[lo]==L[ro])cnum[o]--;
}
void build(int l,int r,int o)
{
if(l==r)
{
cnum[o]=;tag[o]=-;
L[o]=R[o]=col[l];
return;
}
int mid=(l+r)>>,lo=o<<,ro=lo|;
build(l,mid,lo);build(mid+,r,ro);
pushup(l,r,o);tag[o]=-;
}
void update(int l,int r,int o,int a,int b,int c)
{
if(l==a && r==b)
{
tag[o]=c;cnum[o]=;
L[o]=R[o]=c;
return;
}
pushdown(l,r,o);
int mid=(l+r)>>,lo=o<<,ro=lo|;
if(b<=mid)update(l,mid,lo,a,b,c);
else if(a>mid)update(mid+,r,ro,a,b,c);
else
{
update(l,mid,lo,a,mid,c);
update(mid+,r,ro,mid+,b,c);
}
pushup(l,r,o);
}
int query(int l,int r,int o,int a,int b)
{
if(l==a && r==b)return cnum[o];
int mid=(l+r)>>,lo=o<<,ro=lo|;
pushdown(l,r,o);
if(a>mid)return query(mid+,r,ro,a,b);
else if(b<=mid)return query(l,mid,lo,a,b);
else
{
int ans=query(l,mid,lo,a,mid)+query(mid+,r,ro,mid+,b);
return R[lo]==L[ro] ? ans- : ans;
}
}
int special(int l,int r,int o,int a)
{
if(l==r)return L[o];
pushdown(l,r,o);
int mid=(l+r)>>,lo=o<<,ro=lo|;
if(a<=mid)return special(l,mid,lo,a);
else return special(mid+,r,ro,a);
}
void paint(int a,int b,int c)
{
while(bl[a]!=bl[b])
{
if(deep[bl[a]]<deep[bl[b]])swap(a,b);
update(,n,,id[bl[a]],id[a],c);
a=fa[bl[a]];
}
if(id[a]>id[b])swap(a,b);
update(,n,,id[a],id[b],c);
}
int Query(int a,int b)
{
int sum=;
while(bl[a]!=bl[b])
{
if(deep[bl[a]]<deep[bl[b]])swap(a,b);
sum+=query(,n,,id[bl[a]],id[a]);
if(special(,n,,id[bl[a]])==special(,n,,id[fa[bl[a]]]))sum--;
a=fa[bl[a]];
}
if(id[a]>id[b])swap(a,b);
sum+=query(,n,,id[a],id[b]);
return sum;
}
int main()
{
mem(first,-);
n=read();m=read();
for(int i=;i<=n;i++)w[i]=read();
for(int i=;i<n;i++)a=read(),b=read(),addEdge(a,b);
dfs(,);divide(,);
for(int i=;i<=n;i++)col[id[i]]=w[i];
build(,n,);
while(m--)
{
cin>>tp;a=read();b=read();
if(tp=='C')c=read(),paint(a,b,c);
else printf("%d\n",Query(a,b));
}
return ;
}

[codevs1566]染色的更多相关文章

  1. bzoj2243树链剖分+染色段数

    终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...

  2. 51nod 算法马拉松18 A 染色问题

    染色问题 基准时间限制:1 秒 空间限制:10240 KB 分值: 40 一个n(3<=n<=100)个点的完全图,现在给出n,要求将每条边都染上一种颜色k(1<=k<=n), ...

  3. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

  4. NOIP2008双栈排序[二分图染色|栈|DP]

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  5. 洛谷P1330封锁阳光大学[二分图染色]

    题目描述 曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街.河蟹看到欢快的曹,感到不爽.河蟹决定封锁阳光大学,不让曹刷街. 阳光大学的校园是一张由N个点构成的无向图,N个点之间由M ...

  6. POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]

    Knights of the Round Table Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 12439   Acce ...

  7. NOIP2010关押罪犯[并查集|二分答案+二分图染色 | 种类并查集]

    题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示 ...

  8. POJ1112 Team Them Up![二分图染色 补图 01背包]

    Team Them Up! Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7608   Accepted: 2041   S ...

  9. UVALive 4849 String Phone(2-sat、01染色)

    题目一眼看去以为是4-sat... 题意:给n(n<=3000)个黑方块的坐标,保证黑方块没有公共边.对于每个黑方块选一个角作为结点,使得所选结点满足输入的一个无向图.其中距离为曼哈顿距离.输出 ...

随机推荐

  1. Leetcode 第135场周赛解题报告

    这周比赛的题目很有特点.几道题都需要找到一定的技巧才能巧妙解决,和以往靠数据结构的题目不太一样. 就是如果懂原理,代码会很简单,如果暴力做,也能做出来,但是十分容易出错. 第四题还挺难想的,想了好久才 ...

  2. vue系列--vue是如何实现绑定事件

    一.前言 vuejs中的事件绑定,使用<v-on:事件名 = 函数名>来完成的,这里函数名是定义在Vue实例中的methods对象中的,Vue实例可以直接访问其中的方法. 二.事件绑定方式 ...

  3. odoo action

    动作的加载: 刷新视图页面执行load_views方法 /web/dataset/call_kw/model_name/load_views 在odoo/models.py的BaseModel中有一个 ...

  4. 【layui】【laydate】设置可以选择相同的年份范围

    1.效果: 2.解决方法: 修改laydate.js源码 全局查询T.prototype.setBtnStatus这个只有一个,就是点击控件时调用的事件,里面添加下面代码 if( this.confi ...

  5. GitHUB帐号申请及相关操作

    GitHUB帐号申请及相关操作 GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub.GitHub 于 2008 年 4 月 10 ...

  6. 【学习笔记】薛定谔的喵咪Cat—球盒问题(全详解)

    [学习笔记]薛定谔的喵咪Cat-球盒问题(全详解) [题目描述] 当一个猫在盒子里时,因为放射物的状态我们不知道,所以猫的状态我们也不知道,这就所谓猫的生死纠缠态,也是所谓的薛定谔的猫. 当我们做需要 ...

  7. service的yaml说明

    apiVersion: v1 kind: Service metadata: name: nginx-service labels: app: nginx spec: ports: - port: 8 ...

  8. Mysql系列(五)—— 分页查询及问题优化

    一.用法 在Mysql中分页查询使用关键字limit.limit的语法如下: SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15 limit关键字带有 ...

  9. 【02】Kubernets:使用 kubeadm 部署 K8S 集群

    写在前面的话 通过上一节,知道了 K8S 有 Master / Node 组成,但是具体怎么个组成法,就是这一节具体谈的内容.概念性的东西我们会尽量以实验的形式将其复现. 部署 K8S 集群 互联网常 ...

  10. HBase统计表行数(RowCount)的四种方法

    背景:对于其他数据存储系统来说,统计表的行数是再基本不过的操作了,一般实现都非常简单:但对于HBase这种key-value存储结构的列式数据库,统计 RowCount 的方法却有好几种不同的花样,并 ...