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

一眼:链剖
两眼:链剖+两个区间相邻处特判
和学长说了一句:感觉不是很难写(flag)
然后我处理的时候是直接当区间修改时用for循环将线段树区间更新
……正确性当然可以保证啦……出乎意料的是并没有T飞……就T了一个点
去隔壁请教了学长被告知要维护线段树的两端颜色……
于是开始了漫长的调试……
其实这个题只要想到了维护两端的值就很好搞了啊……
哪怕像我想不到维护两端也有95可拿对不对【滑稽】

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define MAX (150000+5)
using namespace std;
struct node
{
int down;//下传标记
int sum;//该区间有几种颜色
int l,r;//该区间左右端点的颜色
} Segt[MAX*];
struct node1
{
int to;
int next;
} edge[MAX*];
int Father[MAX],Depth[MAX];
int Sum[MAX],Son[MAX],Top[MAX];
int TREE[MAX],T_NUM[MAX];
int num_edge,head[MAX],n,cnt;
int a[MAX]; inline int get()//神TM快读,维护左右颜色前卡常用的但没卡过去
{
char c;
int x=,f=;
c=getchar();
while (c<''||c>'')
{
if (c=='-') f=-;
c=getchar();
}
while (c>=''&&c<='')
{
x=x*+c-'';
c=getchar();
}
return x*f;
} void add(int u,int v)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
head[u]=num_edge;
} void Build(int node,int l,int r)
{
if (l==r)
{
Segt[node].sum=;
Segt[node].l=Segt[node].r=TREE[l];
}
else
{
int mid=(l+r)/;
Build(node*,l,mid);
Build(node*+,mid+,r);//这里维护好麻烦啊……早知道写个pushup了
Segt[node].l=Segt[node*].l;
Segt[node].r=Segt[node*+].r;
Segt[node].sum=Segt[node*].sum+Segt[node*+].sum-(Segt[node*].r==Segt[node*+].l);
}
} void Pushdown(int node)
{
if (Segt[node].down!=)
{
Segt[node*].sum=;//因为修改成了一个数所以肯定只有一种颜色
Segt[node*+].sum=; Segt[node*].down=Segt[node].down;//down存下传的颜色编号
Segt[node*+].down=Segt[node].down; Segt[node*].l=Segt[node*].r=Segt[node].down;
Segt[node*+].l=Segt[node*+].r=Segt[node].down; Segt[node].down=;
}
} int Query(int node,int l,int r,int l1,int r1)
{
if (r<l1 || l>r1)
return ;
if (l1<=l && r<=r1)
return Segt[node].sum;
Pushdown(node);
int mid=(l+r)/;
int x=Query(node*,l,mid,l1,r1);
int y=Query(node*+,mid+,r,l1,r1);
if (x!= && y!=)
return x+y-(Segt[node*].r==Segt[node*+].l);
return max(x,y);
} void Update(int node,int l,int r,int l1,int r1,int k)//区间更新模板
{
if (r<l1 || l>r1)
return;
if (l1<=l && r<=r1)
{
Segt[node].down=k;
Segt[node].sum=;
Segt[node].l=Segt[node].r=k;
return;
}
Pushdown(node);
int mid=(l+r)/;
Update(node*,l,mid,l1,r1,k);
Update(node*+,mid+,r,l1,r1,k);//再一次后悔没写pushup
Segt[node].l=Segt[node*].l;
Segt[node].r=Segt[node*+].r;
Segt[node].sum=Segt[node*].sum+Segt[node*+].sum-(Segt[node*].r==Segt[node*+].l);
} int Ask(int node,int l,int r,int x)//查询某个点的颜色
{
if (l==r)
return Segt[node].l;
else
{
Pushdown(node);
int mid=(l+r)/;
if (x<=mid) return Ask(node*,l,mid,x);
else return Ask(node*+,mid+,r,x);
}
} int Get(int x,int y)
{
int fx=Top[x],fy=Top[y];
int Ans=;
while (fx!=fy)
{
if (Depth[fx]<Depth[fy])
swap(fx,fy),swap(x,y);
int re=Ask(,,n,T_NUM[fx]);
int fun=Ask(,,n,T_NUM[Father[fx]]);
Ans+=Query(,,n,T_NUM[fx],T_NUM[x])-(re==fun);
x=Father[fx],fx=Top[x];
}
if (Depth[x]<Depth[y])
swap(x,y);
return Ans+=Query(,,n,T_NUM[y],T_NUM[x]);
} void Change(int x,int y,int k)
{
int fx=Top[x],fy=Top[y];
while (fx!=fy)
{
if (Depth[fx]<Depth[fy])
swap(fx,fy),swap(x,y);
Update(,,n,T_NUM[fx],T_NUM[x],k);
x=Father[fx],fx=Top[x];
}
if (Depth[x]<Depth[y])
swap(x,y);
Update(,,n,T_NUM[y],T_NUM[x],k);
} void Dfs1(int x)
{
Depth[x]=Depth[Father[x]]+;
Sum[x]=;
for (int i=head[x]; i!=; i=edge[i].next)
if (edge[i].to!=Father[x])
{
Father[edge[i].to]=x;
Dfs1(edge[i].to);
Sum[x]+=Sum[edge[i].to];
if (Son[x]== || Sum[Son[x]]<Sum[edge[i].to])
Son[x]=edge[i].to;
}
} void Dfs2(int x,int pre)
{
TREE[++cnt]=a[x];
T_NUM[x]=cnt;
Top[x]=pre;
if (Son[x]!=)
Dfs2(Son[x],pre);
for (int i=head[x]; i!=; i=edge[i].next)
if (edge[i].to!=Son[x] && edge[i].to!=Father[x])
Dfs2(edge[i].to,edge[i].to);
} int main()
{
char ch;
int x,y,k,m,u,v;
n=get();
m=get();
for (int i=; i<=n; ++i)
a[i]=get();
for (int i=; i<=n-; ++i)
{
u=get();
v=get();
add(u,v);
add(v,u);
}
Dfs1();
Father[]=;
Dfs2(,);
Build(,,n);
for (int i=; i<=m; ++i)
{
ch=getchar();
while (ch!='C'&&ch!='Q') ch=getchar();
if (ch=='Q')
x=get(),y=get(),printf("%d\n",Get(x,y));
else
x=get(),y=get(),k=get(),Change(x,y,k);
}
}

2243. [SDOI2011]染色【树链剖分】的更多相关文章

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

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

  2. bzoj-2243 2243: [SDOI2011]染色(树链剖分)

    题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6267  Solved: 2291 Descript ...

  3. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

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

  4. BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  5. BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

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

  6. 2243: [SDOI2011]染色(树链剖分+线段树)

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

  7. BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分的点剖分+线段树.漏了一个小地方,调了一下午...... 还是要细心啊! 结 ...

  8. [bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]

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

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

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

  10. POJ 2243 [SDOI2011]染色 | 树链剖分+线段树

    原题链接 肯定是树链剖分的题啦 树剖怎么做可以看我上一篇博客 如果我们已经剖完了: 然后考虑怎么维护重链和查询 用线段树维护的时候当前区间的区间颜色个数应该等于左儿子+右儿子,但是当左儿子的右端点和右 ...

随机推荐

  1. 如何在HTML 5中拖动光标图标?

    window.app = { dragging: false, config: { canDrag: false, cursorOffsetX: null, cursorOffsetY: null } ...

  2. Open JDk 源码下载地址

    OpenJDK 和Oracle JDK 共用了大量相同的代码,在性能.功能和执行逻辑上都和Oracle JDK非常一致,由于 现在Oracle JDK是闭源的,我们可以下载Open JDK的源码来研究 ...

  3. 针对Eclipse闪退的两种解决方案

    闪退情况是:双击Eclipse登陆按钮,显示图标后,紧接着关闭: 1. 到eclipse文件夹中的eclipse.ini打开编辑在最后加入下面代码保存即可 -Dorg.eclipse.swt.brow ...

  4. Java Tools &Tools APIs

    java 启动Java应用程序 javac Java编译器javac读取用Java编写的源文件,并将它们编译为字节码类文件. 用法: javac <options> <source ...

  5. Myeclipse默认编码设置

    Myeclipse默认编码设置 由于编码问题的出现,我们就必须明确自己在Myeclipse所写的各种文件是按照什么格式来进行编码的.所以只有知己知彼,才能bug少出. 对于刚接触MyEclipse的不 ...

  6. ReadWriteLock

    ReadWriteLock也是一个接口,只有两个方法 一个用来获取读锁,一个用来获取写锁.也就是说将文件的读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作.下面的Reentra ...

  7. 【1】Singleton模式(单例模式)

    一.单例模式的介绍 说到单例模式,大家第一反应应该就是--什么是单例模式?从“单例”字面意思上理解:一个类只有一个实例.所以单例模式也就是保证一个类只有一个实例的一种实现方法罢了(设计模式其实就是帮助 ...

  8. 详解php常量const与define的区别和实例

    所谓常量是一个简单的标识符.在脚本执行期间该值不能改变.常量默认大小写敏感.通常常量标识符总是大写的.常量只能包含标量数据(boolean.integer.float和string).可以定义reso ...

  9. 使用手机预览移动端项目(Vue)

    1.在 npm run dev 启动Vue项目之后.例:http://localhost:8095/#/chatList 2.查看本机的 IP (WIN + R + cmd ) 输入 ipconfig ...

  10. samba 使用tips

    安装: 推荐使用新立德包管理器安装 SAMBA配置文件: /etc/samba/smb.conf Samba服务器的启动与关闭: sudo /etc/init.d/smbd start ubuntu访 ...