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

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. Echarts 学习系列(3)-Echarts动态数据交互

    写在前面 上一小节,我们总结了折线(面积)图.柱状(条形)图.饼(圆环)图类型的图表. 但是,都是静态的.接下来的,这一小节,总结的是Echarts 动态数据的交换. 前置条件 开发环境:win10 ...

  2. node_exporte新版本指标名称变化说明

    changelog如下 Breaking changes This release contains major breaking changes to metric names. Many metr ...

  3. Mybatis架构与原理

    一.简介 MyBatis 是一款优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 Mybatis可以将Sql语句配置在XML文件中,避免将Sql语句硬编码 ...

  4. xmlhttp.status的值及解释

      100——客户必须继续发出请求 101——客户要求服务器根据请求转换HTTP协议版本 200——交易成功 201——提示知道新文件的URL 202——接受和处理.但处理未完成 203——返回信息不 ...

  5. HttpURLConnection Get和Post发送数据

    Get URL url = new URL(path); HttpURLConnection connection = (HttpURLConnection) url.openConnection() ...

  6. OCR1:开源库

    OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别方法将形状翻译 ...

  7. 排序算法的c++实现——归并排序

    归并排序是典型分治思想的代表——首先把原问题分解为两个或多个子问题,然后求解子问题的解,最后使用子问题的解来构造出原问题的解. 对于归并排序,给定一个待排序的数组,首先把该数组划分为两个子数组,然后对 ...

  8. prometheus学习系列一: Prometheus简介

    Prometheus简介 prometheus受启发于Google的Brogmon监控系统(相似kubernetes是从Brog系统演变而来), 从2012年开始由google工程师Soundclou ...

  9. 《linux就该这么学》课堂笔记07 while、case、计划任务、用户增删改查命令

    while条件循环语句 while 条件测试操作 do 命令序列 done  case条件测试语句 case 变量值 in 模式一) 命令序列1 ;; 模式二) 命令序列2 ;; *) 默认命令序列 ...

  10. PySpark DataFrame 添加自增 ID

    PySpark DataFrame 添加自增 ID 本文原始地址:https://sitoi.cn/posts/62634.html 在用 Spark 处理数据的时候,经常需要给全量数据增加一列自增 ...