洛谷P2486 [SDOI2011]染色
题目描述

输入输出格式
输入格式:

输出格式:
对于每个询问操作,输出一行答案。
输入输出样例
输入样例#1:
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
输出样例#1:
3
1
2
说明


思路:对于题目中的操作\(1\),我们可以用树链剖分来实现,就是树链剖分的基本操作,难点就在于操作\(2\),这个操作是要求求任意两点间的颜色段数量,单纯的用线段树维护区间和肯定是不行的,那么就考虑去重,去重机制是怎样的呢?就是我们记录一个\(lc\)表示一个区间的左端点颜色是什么,\(rc\)表示一个区间的右端点颜色是什么,但我们合并左右区间时,如果\(lc[rs]=rc[ls]\),那么这时候就会出现重复,\(ans\)就要\(-1\)。还有就是在进行树链剖分的时候,在不断往上跳的过程中也会出现类似的重复,具体实现看代码。
代码:
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<iostream>
#define maxn 100007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
int n,m,head[maxn],d[maxn],size[maxn],son[maxn],w[maxn];
int cnt,num,top[maxn],sum[maxn<<2],lazy[maxn<<2];
int lc[maxn<<2],rc[maxn<<2],fa[maxn],id[maxn],a[maxn];
char s;
inline int qread() {
char c=getchar();int num=0,f=1;
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) num=num*10+c-'0';
return num*f;
}
struct node {
int v,nxt;
}e[maxn<<1];
inline void ct(int u, int v) {
e[++num].v=v;
e[num].nxt=head[u];
head[u]=num;
}
void dfs1(int u, int f) {
size[u]=1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v!=f) {
d[v]=d[u]+1;
fa[v]=u;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
}
void dfs2(int u, int t) {
id[u]=++cnt;
a[cnt]=w[u];
top[u]=t;
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
inline void pushup(int rt) {
sum[rt]=sum[ls]+sum[rs]-(lc[rs]==rc[ls]);
rc[rt]=rc[rs];
lc[rt]=lc[ls];
}
void build(int rt, int l, int r) {
if(l==r) {
sum[rt]=1;
lc[rt]=rc[rt]=a[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
inline void pushdown(int rt) {
if(lazy[rt]) {
sum[ls]=sum[rs]=1;
lazy[ls]=lazy[rs]=lc[ls]=lc[rs]=rc[ls]=rc[rs]=lazy[rt];
lazy[rt]=0;
}
}
void modify(int rt, int l, int r, int L, int R, int val) {
if(L>r||R<l) return;
if(L<=l&&r<=R) {
sum[rt]=1;
lc[rt]=rc[rt]=lazy[rt]=val;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid) modify(ls,l,mid,L,R,val);
if(R>mid) modify(rs,mid+1,r,L,R,val);
pushup(rt);
}
int csum(int rt, int l, int r, int L, int R) {
if(L>r||R<l) return 0;
if(L<=l&&r<=R) return sum[rt];
pushdown(rt);
int mid=(l+r)>>1;
int ans=0,js=0;
if(L<=mid) ans+=csum(ls,l,mid,L,R),js++;
if(R>mid) ans+=csum(rs,mid+1,r,L,R),js++;
if(js==2) ans-=(rc[ls]==lc[rs]);
return ans;
}
int cx(int rt, int l, int r, int L) {
if(l==r) return lc[rt];
int mid=(l+r)>>1;
pushdown(rt);
if(L<=mid) return cx(ls,l,mid,L);
else return cx(rs,mid+1,r,L);
}
void cal(int x, int y, int val) {
int fx=top[x],fy=top[y];
while(fx!=fy) {
if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
modify(1,1,cnt,id[fx],id[x],val);
x=fa[fx],fx=top[x];
}
if(id[x]>id[y]) swap(x,y);
modify(1,1,cnt,id[x],id[y],val);
}
int query(int x, int y) {
int fx=top[x],fy=top[y],ans=0;
int ans1=0,ans2=0;
while(fx!=fy) {
if(d[fx]<d[fy]) swap(x,y),swap(fx,fy),swap(ans1,ans2);
ans+=csum(1,1,cnt,id[fx],id[x]);
ans-=(cx(1,1,cnt,id[x])==ans1);
ans1=cx(1,1,cnt,id[fx]);
x=fa[fx],fx=top[x];
}
if(id[x]>id[y]) swap(x,y),swap(ans1,ans2);
ans+=csum(1,1,cnt,id[x],id[y]);
if(cx(1,1,cnt,id[x])==ans1) --ans;
if(cx(1,1,cnt,id[y])==ans2) --ans;
return ans;
}
int main() {
n=qread(),m=qread();
for(int i=1;i<=n;++i) w[i]=qread();
for(int i=1,u,v;i<n;++i) {
u=qread(),v=qread();
ct(u,v);ct(v,u);
}
d[1]=1;dfs1(1,0);dfs2(1,1);build(1,1,n);
for(int i=1,x,y,c;i<=m;++i) {
cin>>s;x=qread(),y=qread();
if(s=='C') {
c=qread();
cal(x,y,c);
}
else printf("%d\n",query(x,y));
}
return 0;
}
洛谷P2486 [SDOI2011]染色的更多相关文章
- 洛谷 P2486 [SDOI2011]染色 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 PushDown与Update Q AC代码 总结与拓展 题面 题目链接 P2486 ...
- 洛谷 P2486 [SDOI2011]染色/bzoj 2243: [SDOI2011]染色 解题报告
[SDOI2011]染色 题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同 ...
- 洛谷 P2486 [SDOI2011]染色 LCT
Code: #include <cstdio> //SDOI2010 染色 #include <algorithm> #include <cstring> #inc ...
- 洛谷P2486 [SDOI2011]染色 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2486 首先这是一道树链剖分+线段树的题. 线段树部分和 codedecision P1112 区间连续段 一模一样,所以我们 ...
- 洛谷 P2486 [SDOI2011]染色(树链剖分+线段树)
题目链接 题解 比较裸的树链剖分 好像树链剖分的题都很裸 线段树中维护一个区间最左和最右的颜色,和答案 合并判断一下中间一段就可以了 比较考验代码能力 Code #include<bits/st ...
- 洛谷 P2486 [SDOI2011]染色
题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例#1: 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C ...
- 洛谷P2486 [SDOI2011]染色(树链剖分+线段树判断边界)
[题目链接] [思路]: 涉及到树上区间修改操作,所以使用树链剖分,涉及到区间查询,所以使用线段树. update操作时,就正常操作,难点在于query操作的计数. 因为树链剖分的dfs序只能保证一条 ...
- 洛谷$P2486\ [SDOI2011]$染色 线段树+树链剖分
正解:线段树+树链剖分 解题报告: 传送门$QwQ$ 其实是道蛮板子的题,,,但因为我写得很呆然后写了贼久之后发现想法有问题要重构,就很难受,就先写个题解算了$kk$ 考虑先跑个树剖,然后按$dfn$ ...
- BZOJ2243 洛谷2486 [SDOI2011]染色 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2243 题目传送门 - 洛谷2486 题意概括 一棵树,共n个节点. 让你支持以下两种操作,共m次操 ...
随机推荐
- 关于c++中局部变量和全局变量的存储位置及内存回收机制
局部变量,参数变量存放在栈中,当离开作用范围后,分配的内存在作用范围外会被系统自动回收. new出来的内存空间存放在堆中,不受作用域管理,不会被系统自动回收,只有在使用delete删除或者整个程序结束 ...
- do-while-zero 结构在宏定义中的应用
do while 语句在使用宏定义时是一个有用的技巧,说明如下: 假设有这样一个宏定义 #define macro(condition) / if(condition) dosomething() 现 ...
- ACM学习历程—HDU5637 Transform(数论 && 最短路)
题目链接:http://codeforces.com/problemset/problem/590/A 题目大意是给两种操作,然后给你一个s,一个t,求s至少需要多少次操作到t. 考虑到第一种操作是将 ...
- ACM学习历程—HDU 5443 The Water Problem(RMQ)(2015长春网赛1007题)
Problem Description In Land waterless, water is a very limited resource. People always fight for the ...
- ACM学习历程——UVA 127 "Accordian" Patience(栈;模拟)
Description ``Accordian'' Patience You are to simulate the playing of games of ``Accordian'' patie ...
- VC++6.0注释快捷键的添加使用
在eclipse等编辑工具中都有注释代码的快捷键,但是vc++6.0没有. vc++是以VB为脚本来控制的,在网上找到了一个VB的脚本供大家使用. 工具/原料 VC++6.0 方法/步骤 打开VC ...
- xml schema 中如何定义类似Map的结构
利用xs:unique关键字.在xs:element里添加unique节点,任意命名,然后用xs:selector来选择需要唯一的域, xs:field 里指定特定的字段. 例如:定义所有Item里的 ...
- 三、kafka主要配置
1.Broker配置 <ignore_js_op> 2.Consumer主要配置 <ignore_js_op> 3.Producer主要配置 <ignor ...
- 使用tftp给ARM下载程序
使用tftp给ARM下载程序 1.开发板和主机能够ping的通 前提:要把计算机的防火墙关了,不然就会出现下面这种情况 如果电脑连接的无线网,那么设置本地连接的ip设置为固定ip.Ip地址和开发的ip ...
- 用paramiko写堡垒机
paramiko paramiko模块,基于SSH用于连接远程服务器并执行相关操作. 基本用法 SSHClient 基于用户名密码连接: 基础用法: import paramiko # 创建SSH对象 ...