[bzoj 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,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
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
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
My Solution
一道可爱的树链剖分题啊
注意区间合并和树剖中的calc即可
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; inline int read(){
char ch;
int re=;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=re*+ch-'';
return flag?-re:re;
} inline char rea(){
char ch;
while((ch=getchar())!='Q'&&ch!='C');
return ch;
} struct edge{
int to,next;
edge(int to=,int next=):
to(to),next(next){}
}; struct segment{
int l,r,lc,rc,sum,tag;
}; const int maxn=1e5+; edge edges[maxn<<];
segment tre[maxn<<];
int n,m,cnt=,root;
//si1,si2表示query操作中取到的最高和最低颜色
int si1,si2,LL,RR;
int head[maxn],data[maxn];
int siz[maxn],fat[maxn],son[maxn],dep[maxn],id[maxn],id_[maxn],top[maxn]; inline void add_edge(int from,int to){
edges[++cnt]=edge(to,head[from]); head[from]=cnt;
edges[++cnt]=edge(from,head[to]); head[to]=cnt;
} void init(){
n=read(); m=read();
for(int i=;i<=n;i++) data[i]=read();
int from,to; cnt=;
for(int i=;i<n;i++){
from=read(); to=read();
add_edge(from,to);
}
} void dfs_1(int x,int fa){
siz[x]=;
dep[x]=dep[fa]+;
fat[x]=fa;
for(int ee=head[x];ee;ee=edges[ee].next)
if(edges[ee].to!=fa){
dfs_1(edges[ee].to,x);
siz[x]+=siz[edges[ee].to];
if(!son[x]||siz[edges[ee].to]>siz[son[x]]) son[x]=edges[ee].to;
}
} void dfs_2(int x,int first){
top[x]=first;
id[x]=++cnt;
id_[cnt]=x;
if(!son[x]) return;
dfs_2(son[x],first);
for(int ee=head[x];ee;ee=edges[ee].next)
if(edges[ee].to!=fat[x]&&edges[ee].to!=son[x]) dfs_2(edges[ee].to,edges[ee].to);
} void push_up(int x){
int lson=x<<,rson=lson|;
tre[x].lc=tre[lson].lc;
tre[x].rc=tre[rson].rc;
tre[x].sum=tre[lson].sum+tre[rson].sum-(tre[lson].rc==tre[rson].lc?:);
} void build(int x,int l,int r){
tre[x].l=l; tre[x].r=r;
if(l==r){
tre[x].lc=tre[x].rc=data[id_[l]];
tre[x].sum=;
return;
}
int mid=(l+r)>>;
build(x<<,l,mid); build(x<<|,mid+,r);
push_up(x);
} void push_down(int x){
int lson=x<<,rson=lson|;
int &c=tre[x].tag;
tre[lson].tag=tre[rson].tag=tre[lson].lc=
tre[lson].rc=tre[rson].lc=tre[rson].rc=c;
tre[lson].sum=; tre[rson].sum=;
c=;
} void make(){
root=; dfs_1(root,);
cnt=; dfs_2(root,root);
build(,,n);
} void update(int x,int L,int R,int c){
if(L<=tre[x].l&&tre[x].r<=R){
tre[x].lc=tre[x].rc=tre[x].tag=c;
tre[x].sum=;
return;
} if(tre[x].tag) push_down(x); int mid=(tre[x].l+tre[x].r)>>;
if(R<=mid) update(x<<,L,R,c);
else if(L>mid) update(x<<|,L,R,c);
else{
update(x<<,L,mid,c);
update(x<<|,mid+,R,c);
}
push_up(x);
} int query_sum(int x,int L,int R){
if(tre[x].l==LL) si1=tre[x].lc;
if(tre[x].r==RR) si2=tre[x].rc;
if(L<=tre[x].l&&tre[x].r<=R) return tre[x].sum; if(tre[x].tag) push_down(x); int mid=(tre[x].l+tre[x].r)>>;
if(R<=mid) return query_sum(x<<,L,R);
if(L>mid) return query_sum(x<<|,L,R);
return query_sum(x<<,L,mid)+query_sum(x<<|,mid+,R)-(tre[x<<].rc==tre[x<<|].lc?:);
} void calc(int ss,int tt,int c){
int f1=top[ss],f2=top[tt];
while(f1!=f2){
if(dep[f1]<dep[f2]){ swap(f1,f2); swap(ss,tt); }
update(,id[f1],id[ss],c);
ss=fat[f1]; f1=top[ss];
}
if(dep[ss]<dep[tt]) swap(ss,tt);
update(,id[tt],id[ss],c);
} int calc(int ss,int tt){
int f1=top[ss],f2=top[tt],ans=;
int sid1=,sid2=;
while(f1!=f2){
if(dep[f1]<dep[f2]){ swap(f1,f2); swap(ss,tt); swap(sid1,sid2); }
LL=id[f1]; RR=id[ss];
ans+=query_sum(,id[f1],id[ss]);
if(si2==sid1) ans--;
sid1=si1; ss=fat[f1]; f1=top[ss];
}
if(dep[ss]<dep[tt]) { swap(ss,tt); swap(sid1,sid2); }
LL=id[tt]; RR=id[ss];
ans+=query_sum(,id[tt],id[ss]);
if(sid1==si2) ans--;
if(sid2==si1) ans--;
return ans;
} void solve(){
char opt;
int ss,tt,c;
for(int i=;i<m;i++){
opt=rea();
switch(opt){
case 'C':{
ss=read(); tt=read(); c=read();
calc(ss,tt,c);
break;
}
case 'Q':{
ss=read(); tt=read();
printf("%d\n",calc(ss,tt));
break;
}
}
}
} int main(){
//freopen("data.in","r",stdin);
init();
make();
solve();
return ;
}
それまでは 閉じこもって
あなたも卵の中なのね
[bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]的更多相关文章
- 2243: [SDOI2011]染色 树链剖分+线段树染色
给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- B20J_2243_[SDOI2011]染色_树链剖分+线段树
B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...
- BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)
题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- bzoj 2157: 旅游【树链剖分+线段树】
裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...
随机推荐
- 多线程异步编程示例和实践-Thread和ThreadPool
说到多线程异步编程,总会说起Thread.ThreadPool.Task.TPL这一系列的技术.总结整理了一版编程示例和实践,分享给大家. 先从Thread和ThreadPool说起: 1. 创建并启 ...
- Centos 执行shell命令返回127错误
shell脚本功能:连接mysql,自动创建数据库,脚本如下 mysql -h$MYSQL_IP -u$MYSQL_USER -p$MYSQL_PASSWORD --default-character ...
- Centos 环境一键部署脚本(shell脚本)
谨以此文纪念吊炸天的Centos环境一键部署方案的新鲜出炉 辛苦大半年,产品准备上线了,BOSS亲自体验安装部署,看着超过200+页的安装文档直接崩溃了(需要部署23个基础服务),经历了超过3个小时的 ...
- iOS自定义弹出视图
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #78492a } p.p2 { margin: 0.0px 0. ...
- 用javascript实现java的Map
function Map(){ var obj={}; //空的容器 //put方法 this.put=function(key,value){ obj[key]=value; //把键值绑定到obj ...
- 用php+mysql+ajax实现淘宝客服或阿里旺旺聊天功能 之 前台页面
首先来看一下我已经实现的效果图: 消费者页面:(本篇随笔) (1)会显示店主的头像 (2)当前用户发送信息显示在右侧,接受的信息,显示在左侧 店主或客服页面:(下一篇随笔) (1)在左侧有一个列表 , ...
- Bash中单引号和双引号的区别
单引号和双引号的区别 单引号:必须成对使用,它可以保护所有的字符不被翻译.如变量$1,和奇数个单引号的作用相同,偶数个单引号=1个双引号双引号:必须成对出现,它可以保护一些元字符不被翻译,但允许变量和 ...
- NetCore1.1+Linux部署初体验
1.环境准备 Centaos7+Win10 虚拟机 Win10安装VS2017 https://www.asp.net/downloads注意勾选下.Net Core 3.Centaos安装netco ...
- 基于Spring的最简单的定时任务实现与配置(一)
朋友的项目中有点问题.他那边是Spring架构的,有一个比较简单的需要定时的任务执行.在了解了他的需求之后,于是提出了比较简单的Spring+quartz的实现方式. 注意本文只是讨论,在已搭建完毕的 ...
- Python数据类型及其方法详解
Python数据类型及其方法详解 我们在学习编程语言的时候,都会遇到数据类型,这种看着很基础也不显眼的东西,却是很重要,本文介绍了python的数据类型,并就每种数据类型的方法作出了详细的描述,可供知 ...