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

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

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

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]染色 [树链剖分][线段树]的更多相关文章

  1. 2243: [SDOI2011]染色 树链剖分+线段树染色

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

  2. bzoj2243[SDOI2011]染色 树链剖分+线段树

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

  3. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  4. B20J_2243_[SDOI2011]染色_树链剖分+线段树

    B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...

  5. BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

    题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...

  6. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  7. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  8. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  9. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  10. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

随机推荐

  1. struts2+hibernate+spring注解版框架搭建以及简单测试(方便脑补)

    为了之后学习的日子里加深对框架的理解和使用,这里将搭建步奏简单写一下,目的主要是方便以后自己回来脑补: 1:File--->New--->Other--->Maven--->M ...

  2. php简单的文件操作

    (1)先要想好要操作哪个文件? (2)确定文件的路径? (3)要有什么文件管理功能? 一.先做一下简单的查看文件功能,文件中的文件和文件夹都显示,但是双击文件夹可以显示下一级子目录,双击"返 ...

  3. Java中的static、final关键字

    static static 的含义是静态的,是一个静态修饰符,一般来说,被static修饰的有以下几种,类.变量.方法.代码块. static修饰类 Java中普通的类是不允许被声明为静态的,但是有一 ...

  4. JavaScript函数认识,Js中的常见函数

    JavaScript函数: 也称为方法,用来存储一块代码,需要的时候调用. 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块. 函数需要包含四要素:返回类型,函数名,参数列表,函数体 拓展: ...

  5. [1] C# IS & AS讲解

    c# 中 is和as 操作符是用来进行强制类型转换的 is : 检查一个对象是否兼容于其他指定的类型,并返回一个Bool值,永远不会抛出异常 object o = new object(); if ( ...

  6. 第二章完结,包含exam练习

    正则方程(Normal Equation) 梯度下降是最小化代价函数\(J(\theta)\)的一种方式,这里提出了另一种方式即正则方式不使用迭代方式:\(\theta = (X^TX)^{-1}X^ ...

  7. sql 注入命令大全

    1.判断有无注入点 ; and 1=1 and 1=2 2.猜表一般的表的名称无非是admin adminuser user pass password 等.. and 0<>(selec ...

  8. scrapy初试

    scrapy初试 创建项目 打开cmd,在终端输入scrapy startproject tutorial,这里将在指定的文件夹下创建一个scrapy工程 其中将会创建以下的文件: scrapy.cf ...

  9. PHP+MySql实现后台数据的读取

      我们使用的是PHP 的php_mysqli扩展   首先了解一些基础的用法  1.连接数据库使用 mysqli_connect()  参数:①主机地址 ②MYSQL用户名 ③MYSQL密码 ④选择 ...

  10. centos6.7下安装mysql5.6.22同时解决中文乱码问题

    1.下载 http://dev.mysql.com/downloads/mysql/ 或者使用wget下载: wget http://dev.mysql.com/get/Downloads/MySQL ...