BZOJ2243[SDOI2011]染色——树链剖分+线段树
题目描述
输入
输出
对于每个询问操作,输出一行答案。
样例输入
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
2
提示
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
一道很有思维含量且细节挺多的题。首先想如何求序列上一个区间有几个颜色段?线段树每个点维护这个点所代表区间的左右端点颜色及这个区间的颜色段数就好了。在树上操作就直接dfs出树剖序然后架在线段树上。但要注意一点,每次查询时两点在跳lca的过程中每次跳的是一条重链,两条重链的相接的两个点颜色如果相同就要把答案数减1,所以还要维护每次跳的链头的颜色。当最后两个点跳到同一个重链上时这两点间的链的两头要分别判断一下。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int tot;
int num;
int x,y,z;
char ch[2];
int s[100010];
int d[100010];
int a[800010];
int f[100010];
int v[100010];
int q[100010];
int ls[800010];
int rs[800010];
int to[200010];
int sum[800010];
int son[100010];
int top[100010];
int size[100010];
int head[100010];
int next[200010];
void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void dfs(int x,int fa)
{
size[x]=1;
f[x]=fa;
d[x]=d[fa]+1;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dfs(to[i],x);
size[x]+=size[to[i]];
if(size[to[i]]>size[son[x]])
{
son[x]=to[i];
}
}
}
}
void dfs2(int x,int tp)
{
s[x]=++num;
q[num]=x;
top[x]=tp;
if(son[x])
{
dfs2(son[x],tp);
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=f[x]&&to[i]!=son[x])
{
dfs2(to[i],to[i]);
}
}
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
if(rs[rt<<1]==ls[rt<<1|1])
{
sum[rt]--;
}
ls[rt]=ls[rt<<1];
rs[rt]=rs[rt<<1|1];
}
void pushdown(int rt)
{
if(a[rt]!=-1)
{
a[rt<<1]=a[rt];
a[rt<<1|1]=a[rt];
ls[rt<<1]=a[rt];
rs[rt<<1]=a[rt];
ls[rt<<1|1]=a[rt];
rs[rt<<1|1]=a[rt];
sum[rt<<1]=1;
sum[rt<<1|1]=1;
a[rt]=-1;
}
}
void build(int rt,int l,int r)
{
a[rt]=-1;
if(l==r)
{
ls[rt]=rs[rt]=v[q[l]];
sum[rt]=1;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void change(int rt,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
sum[rt]=1;
ls[rt]=v;
rs[rt]=v;
a[rt]=v;
return ;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)
{
change(rt<<1,l,mid,L,R,v);
}
if(R>mid)
{
change(rt<<1|1,mid+1,r,L,R,v);
}
pushup(rt);
}
int query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return sum[rt];
}
pushdown(rt);
int mid=(l+r)>>1;
if(R<=mid)
{
return query(rt<<1,l,mid,L,R);
}
else if(L>mid)
{
return query(rt<<1|1,mid+1,r,L,R);
}
if(rs[rt<<1]==ls[rt<<1|1])
{
return query(rt<<1,l,mid,L,R)+query(rt<<1|1,mid+1,r,L,R)-1;
}
else
{
return query(rt<<1,l,mid,L,R)+query(rt<<1|1,mid+1,r,L,R);
}
}
int find(int rt,int l,int r,int k)
{
if(l==r)
{
return ls[rt];
}
pushdown(rt);
int mid=(l+r)>>1;
if(k<=mid)
{
return find(rt<<1,l,mid,k);
}
else
{
return find(rt<<1|1,mid+1,r,k);
}
}
void color(int x,int y,int v)
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]])
{
swap(x,y);
}
change(1,1,n,s[top[x]],s[x],v);
x=f[top[x]];
}
if(d[x]>d[y])
{
swap(x,y);
}
change(1,1,n,s[x],s[y],v);
}
int ask(int x,int y)
{
int t1=-1;
int s1=-1;
int res=0;
while(top[x]!=top[y])
{
if(d[top[x]]>d[top[y]])
{
res+=query(1,1,n,s[top[x]],s[x]);
if(s1==find(1,1,n,s[x]))
{
res--;
}
s1=find(1,1,n,s[top[x]]);
x=f[top[x]];
}
else
{
res+=query(1,1,n,s[top[y]],s[y]);
if(t1==find(1,1,n,s[y]))
{
res--;
}
t1=find(1,1,n,s[top[y]]);
y=f[top[y]];
}
}
if(x==y)
{
res++;
int miku=find(1,1,n,s[x]);
if(miku==t1)
{
res--;
}
if(miku==s1)
{
res--;
}
}
else
{
if(d[x]>d[y])
{
res+=query(1,1,n,s[y],s[x]);
}
else
{
res+=query(1,1,n,s[x],s[y]);
}
if(find(1,1,n,s[x])==s1)
{
res--;
}
if(find(1,1,n,s[y])==t1)
{
res--;
}
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%s",ch);
if(ch[0]=='C')
{
scanf("%d%d%d",&x,&y,&z);
color(x,y,z);
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",ask(x,y));
}
}
}
BZOJ2243[SDOI2011]染色——树链剖分+线段树的更多相关文章
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
- BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)
题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...
- B20J_2243_[SDOI2011]染色_树链剖分+线段树
B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...
- 2243: [SDOI2011]染色 树链剖分+线段树染色
给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树
题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
随机推荐
- java基础应用循环的应用
1.1 [经典面试题]: &&(短路与)与&(非短路与)的区别: 表达式1 && 表达式2 表达式1如果为false,表达式2不执行,整个表达式结果为false ...
- CMake在Visual Studio下保持目录结构
CMake在Visual Studio下保持目录结构 原理 主要通过CMAKE自带函数source_group来设定. 需要把add_executable()函数进行封装,包裹一层source_gro ...
- 使用layer弹出Ueditor实现父子传值
Layear的代码: function tankuang() { layer.open({ type: 2, title: false ...
- 網管利器!開源管理系統-LibreNMS
https://www.4rbj4.com/442 https://www.ichiayi.com/wiki/tech/librenms
- python之squid实现免费 IP代理 (windows win7 单机 本机 本地 正向代理 区分 HTTPS)
0.目录 1.思路2.windows安装3.相关命令行4.简单配置和初步使用5.问题:squid是否支持HTTPS6.问题:配置多个代理条目,相同ip不同port报错7.问题:根据代理请求区分HTTP ...
- BZOJ4566 [Haoi2016]找相同字符 字符串 SAM
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4566.html 题目传送门 - BZOJ4566 题意 给定两个字符串 $s1$ 和 $s2$ ,问有 ...
- rock-paper-scissors
rock-paper-scissors维护三个前缀和,然后注意顺序,最后做差来确定可行的答案,因为答案比较小,可以考虑这种暴力做法,像这种方案数可以++的题真的不多,如果想不出来特别优秀的想法,不妨简 ...
- oracle 重复只保留一条
DELETE FROM xx WHERE ROWID NOT IN (SELECT MIN(ROWID) FROM xx GROUP BY xx, xx);
- Oracle date 详解
oracle 数据类型详解---日期型 oracle数据类型看起来非常简单,但用起来会发现有许多知识点,本文是我对ORACLE日期数据类型的一些整理,都是开发入门资料,与大家分享:注:由于INTERV ...
- 练习六 向表A批量插入数据
create or replace procedure BATCH_INSERT_A (insertNo in integer) is n_id integer; /***************** ...