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]之间。


--->题目是复制过来的,感觉字体大小很奇怪啊...不管了,先把这道鸽了我好几天的题A掉

这道题呢主要是运用树链剖分和线段树的思想

我们用tree这个结构体来维护线段树中每个节点的左端点的颜色lc、右端点的颜色rc、区间标记col(别忘了标记下传)以及该区间颜色段的数量sum。

以下几点需要特别注意(本题难点):

  • 在区间合并的时候,如果左子树的右端和右子树的左端颜色一致,那么该区间sum--;

  • 在剖链的时候,如果上一条链的左端(即靠近根节点的一端,因为在建树的时候,线段树中越左边的位置越靠近根节点)颜色和当前剖到的链的右段(即远离根节点的一端,两链相交处)颜色一致,那么总颜色数sum--;

  • 当top[x]==top[y],即两点已经在同一条重链上时,两边端点的颜色都应与对应的点进行比较,如颜色一致,同样总颜色数sum--;

详情请见代码:

 #include<bits/stdc++.h>
using namespace std;
const int N=1e6+,inf=0x3f3f3f3f;
int next[*N],head[*N],to[N*],d[N],fa[N],v[*N],seg[*N],rev[*N],top[N],size[N],son[N],w[N];
int n;
int m,q,p,tot,cnt;
int sum,ma;
struct node{
int lc,rc,sum,col;
}tree[N];
void ADD(int k,int l,int r,int v)
{
tree[k].lc=tree[k].rc=v;
tree[k].sum=;
tree[k].col=v;
return ;
}
void pushdown(int k,int l,int r,int mid)
{
if(!tree[k].col)return ;
ADD(k<<,l,mid,tree[k].col);
ADD(k<<|,mid+,r,tree[k].col);
tree[k].col=;
}
void dfs1(int s,int ff)
{
size[s]=;d[s]=d[ff]+;fa[s]=ff;
for(int i=head[s],t;i,t=to[i];i=next[i])
{
if(t!=fa[s])
{
dfs1(t,s);
size[s]+=size[t];
if(size[t]>size[son[s]])son[s]=t;
}
}
}
void dfs2(int s)
{
if(son[s])
{
seg[son[s]]=++seg[];
top[son[s]]=top[s];
rev[seg[]]=son[s];
dfs2(son[s]);
}
for(int i=head[s],t;t=to[i],i;i=next[i])
{
if(!top[t])
{
seg[t]=++seg[];
rev[seg[]]=t;
top[t]=t;
dfs2(t);
}
}
}
void update(int k)
{
tree[k].sum=tree[k<<].sum+tree[k<<|].sum;
if(tree[k<<].rc==tree[k<<|].lc)tree[k].sum--;
tree[k].lc=tree[k<<].lc;
tree[k].rc=tree[k<<|].rc;
}
void build(int k,int l,int r)
{
if(l==r)
{
tree[k].lc=tree[k].rc=w[rev[l]];
tree[k].sum=;
return ;
}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
update(k);
}
node query2(int k,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
{
return tree[k];
}
int mid=l+r>>;
pushdown(k,l,r,mid);
if(mid>=x)
{
if(mid<y)
{
node res,ll=query2(k<<,l,mid,x,y),rr=query2(k<<|,mid+,r,x,y);
res.sum=ll.sum+rr.sum+(ll.rc==rr.lc?-:);
res.lc=ll.lc;res.rc=rr.rc;
return res;
}
else return query2(k<<,l,mid,x,y);
}
else return query2(k<<|,mid+,r,x,y);
}
int query1(int x,int y)
{
//这里可能不是很好理解,但是把a、b当做现任和备胎可能会好想一些(机房大佬lhy指点)
int sum=,a=,b=;
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(d[fx]<d[fy])swap(x,y),swap(fx,fy),swap(a,b);
node res=query2(,,n,seg[fx],seg[x]);
sum+=res.sum;
if(res.rc==a)sum--;
a=res.lc;
x=fa[fx];fx=top[x];
}
if(d[x]>d[y])swap(x,y),swap(a,b);
node res=query2(,,n,seg[x],seg[y]);
sum+=res.sum;
if(res.lc==a) sum--;
if(res.rc==b) sum--;
return sum;
}
int read()
{
int f=;char ch;
while((ch=getchar())<''||ch>'')
if(ch=='-')f=-;
int res=ch-'';
while((ch=getchar())>=''&&ch<='')
res=res*+ch-'';
return res*f;
}
void write(int x)
{
if(x<)
{
putchar('-');
x=-x;
}
if(x>)write(x/);
putchar(x%+'');
}
void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void change2(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y)return ADD(k,l,r,v);
int mid=l+r>>;
pushdown(k,l,r,mid);
if(mid>=x)change2(k<<,l,mid,x,y,v);
if(mid<y)change2(k<<|,mid+,r,x,y,v);
update(k);
}
void change1(int x,int y,int v)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
change2(,,n,seg[fx],seg[x],v);
x=fa[fx];fx=top[x];
}
if(d[x]>d[y])swap(x,y);
change2(,,n,seg[x],seg[y],v);
}
int main()
{
n=read();m=read();
for(int i=;i<=n;i++)w[i]=read();
for(int i=;i<n;i++)
{
int x,y;
x=read();y=read();
add(x,y);add(y,x);
}
dfs1(,);
seg[]=top[]=rev[]=seg[]=;
dfs2();
build(,,n);
while(m--)
{
char ch;int a,b;
while((ch=getchar())<'A'||ch>'Z');
//这个地方读入一定要小心!我的爆零经验就是前车之鉴!!!
a=read();b=read();
if(ch=='C')
{
int c;c=read();
change1(a,b,c);
}
else
{
write(query1(a,b));
putchar('\n');
}
}
return ;
}
//硬生生凑个200行 ~(~ ̄▽ ̄)~

[SDOI2011]染色(信息学奥赛一本通 1563)(洛谷 2486)的更多相关文章

  1. BZOJ2243 洛谷2486 [SDOI2011]染色 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2243 题目传送门 - 洛谷2486 题意概括 一棵树,共n个节点. 让你支持以下两种操作,共m次操 ...

  2. $ybt\ 【信息学奥赛一本通】题解目录$

    [信息学奥赛一本通]题解目录 $ \large -> OJ$ $ problem1000 $ \(Answer\) - > $ \large 1000$ $ problem1001 $ \ ...

  3. 「SDOI2014」旅行(信息学奥赛一本通 1564)(洛谷 3313)

    题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我 ...

  4. 【03NOIP普及组】麦森数(信息学奥赛一本通 1925)(洛谷 1045)

    [题目描述] 形如2P-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2P-1不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的一个是P=3021377,它 ...

  5. 【00NOIP普及组】计算器的改良(信息学奥赛一本通 1910)(洛谷 1022)

    [题目描述] NCL是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委托的一个任务:需要在该公司某型号的计算器上加上解一元一次方程的功能.实验室将这个任务交给了一个刚进入的新手ZL先 ...

  6. 【00NOIP普及组】税收与补贴问题(信息学奥赛一本通 1911)( 洛谷 1023)

    [题目描述] 每样商品的价格越低,其销量就会相应增大.现已知某种商品的成本及其在若干价位上的销量(产品不会低于成本销售),并假设相邻价位间销量的变化是线性的且在价格高于给 定的最高价位后,销量以某固定 ...

  7. 食物链【NOI2001】(信息学奥赛一本通 1390)

    [题目描述] 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种 ...

  8. 【NOI2002】荒岛野人(信息学奥赛一本通 1637)(洛谷 2421)

    题目描述 克里特岛以野人群居而著称.岛上有排列成环行的M个山洞.这些山洞顺时针编号为1,2,…,M.岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi ...

  9. 【09NOIP提高组】Hankson 的趣味题(信息学奥赛一本通 1856)(洛谷 1072)

    题目描述 Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson.现在,刚刚放学回家的Hankson 正在思考一个有趣的问题.今天在课堂上,老师讲解了如何求 ...

随机推荐

  1. 网络编程之模拟ssh远程执行命令、粘包问题 、解决粘包问题

    目录 模拟ssh远程执行命令 服务端 客户端 粘包问题 什么是粘包 TCP发送数据的四种情况 粘包的两种情况 解决粘包问题 struct模块 解决粘包问题 服务端 客户端 模拟ssh远程执行命令 服务 ...

  2. JS项目练习之求和(包含正则表达式验证)

    最近在准备专升本,抽一点时间敷衍一下大家!!!嘿嘿嘿!!! 话不多说,上代码: <!DOCTYPE html> <html lang="zh-CN"> &l ...

  3. 英语insuraunce保险insuraunce单词

    English Alternative forms insuraunce Etymology From the older form ensurance, see also assurance. Pr ...

  4. RabbitMQ基本概念(三)-Centos7下安装RabbitMQ3.6.1

    如果你看过前两章对RabbitMQ已经有了一定了解,现在已经摩拳擦掌,来吧动手吧! 用什么系统 本文使用的是Centos7,为了保证对linux不太熟悉的伙伴也能轻松上手(避免折在安装的路上),下面是 ...

  5. LP线性规划求解 之 单纯形 算法

    LP线性规划求解 之 单纯形 算法 认识-单纯形 核心: 顶点旋转 随机找到一个初始的基本可行解 不断沿着可行域旋转(pivot) 重复2,直到结果不能改进为止 案例-过程 以上篇的case2的松弛型 ...

  6. C# 控制台定时器

    C# 定时器 关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.Windows.Forms里2.定义在System.Threading.Timer类里3.定义在System. ...

  7. 【Linux】在linux上java工具jps jstat jinfo等命令找不到怎么办

    一.yum安装方式 1)搜索openjdk-devel相关的安装包 yum search java|grep jdk 2)安装对应的版本 yum install -y java-1.8.0-openj ...

  8. 浅谈原子操作、volatile、CPU执行顺序

    浅谈原子操作.volatile.CPU执行顺序 在计算机发展的鸿蒙年代,程序都是顺序执行,编译器也只是简单地翻译指令,随着硬件和软件的飞速增长,原来的工具和硬件渐渐地力不从心,也逐渐涌现出各路大神在原 ...

  9. K8S概念理解参考

  10. Redis持久化 - RDB和AOF

    原文:https://segmentfault.com/a/1190000016021217 一.持久化的作用 1. 什么是持久化 持久化(Persistence),即把数据(如内存中的对象)保存到可 ...