luogu P2486 [SDOI2011]染色
树剖做法:
就是两个dfs+一个线段树
难度的取决基本==线段树的维护难度
所以对有点线段树基础的,树剖也不难做吧
这里操作有二
一:两点间路径染色
线段树的区间赋值操作
二:查询路径段的个数
考虑线段树如何做
我们发现两端区间的合并取决于他们相连接的那两个颜色
比如这张图

他两边区间合并的时候,完全就是左区间答案+右区间答案也就是2+2
但是这样

他们合并的答案就是2+2-1了也就是中间连接的两个颜色相同时要减1
明白了这个pushup也就不难写了
这里在说一下查询操作
由于是分开查询的,所以也有可能会中间相同而没有减1
这里就有点套路(技巧?)了,留给你们想吧
光线段树上就完事了吗,当然不是
树链剖分把树给剖了当然会有影响
我们再判断一下两条链之间是否颜色相同就可以了
好了,再不懂就去看一下代码吧
代码
cpp #include <bits/stdc++.h> #define FOR(i,a,b) for(int i=a;i<=b;++i) using namespace std; const int N=100007; int read() { int x=0,f=1;char s=getchar(); for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1; for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0'; return x*f; } int n,m,a[N],col[N],top[N],f[N],son[N],siz[N],dep[N],idx[N],cnt; struct node { int v,nxt; }e[N<<1]; int head[N],tot; void add_edge(int u,int v) { e[++tot].v=v; e[tot].nxt=head[u]; head[u]=tot; } void dfs1(int u,int fa) { dep[u]=dep[fa]+1; siz[u]=1; f[u]=fa; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v==fa) continue; dfs1(v,u); siz[u]+=siz[v]; if(siz[son[u]] < siz[v]) son[u]=v; } } void dfs2(int u,int topf) { idx[u]=++cnt; a[cnt]=col[u]; top[u]=topf; if(!son[u]) return; dfs2(son[u],topf); for(int i=head[u];i;i=e[i].nxt) if(!idx[e[i].v]) dfs2(e[i].v,e[i].v); } namespace seg_tree { #define ls (rt<<1) #define rs (rt<<1|1) struct node { int l,r,lc,rc; int sum,lazy; }e[N<<2]; void pushup(int rt) { if(ls&&rs) { e[rt].sum=e[ls].sum+e[rs].sum-(e[ls].rc==e[rs].lc); e[rt].lc=e[ls].lc; e[rt].rc=e[rs].rc; } else e[rt]=e[ls+rs]; } void build(int l,int r,int rt) { e[rt].l=l,e[rt].r=r; if(l==r) { e[rt].lc=e[rt].rc=a[l]; e[rt].sum=1; return; } int mid=(l+r)>>1; build(l,mid,ls); build(mid+1,r,rs); pushup(rt); } void tag(int rt,int k) { e[rt].lc=e[rt].rc=k; e[rt].sum=1; e[rt].lazy=k; } void pushdown(int rt) { if(e[rt].lazy) { tag(ls,e[rt].lazy); tag(rs,e[rt].lazy); e[rt].lazy=0; } } void modify(int L,int R,int k,int rt) { if(L<=e[rt].l&&e[rt].r<=R) { tag(rt,k); return; } pushdown(rt); int mid=(e[rt].l+e[rt].r)>>1; if(L<=mid) modify(L,R,k,ls); if(R>mid) modify(L,R,k,rs); pushup(rt); } node query(int L,int R,int rt) { if(L<=e[rt].l&&e[rt].r<=R) return e[rt]; pushdown(rt); int mid=(e[rt].l+e[rt].r)>>1; if(L<=mid && R>mid) { node a=query(L,R,ls),b=query(L,R,rs); node c; c.lc=a.lc; c.rc=b.rc; c.sum=a.sum+b.sum-(a.rc==b.lc); return c; } if(L<=mid) return query(L,R,ls); if(R>mid) return query(L,R,rs); } int ask(int L,int rt) { if(e[rt].l==e[rt].r) return e[rt].lc; pushdown(rt); int mid=(e[rt].l+e[rt].r)>>1; if(L<=mid) return ask(L,ls); else return ask(L,rs); } } void CC(int x,int y,int k) { while(top[x]!=top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y); seg_tree::modify(idx[top[x]],idx[x],k,1); x=f[top[x]]; } if(dep[x]>dep[y])swap(x,y); seg_tree::modify(idx[x],idx[y],k,1); } void QQ(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y); ans+=seg_tree::query(idx[top[x]],idx[x],1).sum; ans-=(seg_tree::ask(idx[top[x]],1)==seg_tree::ask(idx[f[top[x]]],1)); x=f[top[x]]; } if(dep[x]>dep[y])swap(x,y); ans+=seg_tree::query(idx[x],idx[y],1).sum; printf("%d\n", ans); } int main() { n=read(),m=read(); FOR(i,1,n) col[i]=read(); FOR(i,2,n) { int x=read(), y=read(); add_edge(x,y); add_edge(y,x); } dfs1(1,0); dfs2(1,1); seg_tree::build(1,n,1); FOR(i,1,m) { char s=getchar(); while(s==' '||s=='\n') s=getchar(); int x=read(), y=read(), z; if(s=='C') z=read(),CC(x,y,z); else QQ(x,y); } return 0; }l
luogu P2486 [SDOI2011]染色的更多相关文章
- Luogu P2486 [SDOI2011]染色(树链剖分+线段树合并)
Luogu P2486 [SDOI2011]染色 题面 题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例: 6 5 2 2 1 2 1 1 1 ...
- P2486 [SDOI2011]染色
P2486 [SDOI2011]染色 树链剖分 用区间修改线段树维护 对于颜色段的计算:sum[o]=sum[lc]+sum[rc] 因为可能重复计算,即左子树的右端点和右子树的左端点可能颜色相同 多 ...
- [Luogu 2486] SDOI2011 染色
[Luogu 2486] SDOI2011 染色 树剖水题,线段树维护. 详细题解不写了. 我只想说我写的线段树又变漂亮了qwq #include <algorithm> #include ...
- 洛谷 P2486 [SDOI2011]染色 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 PushDown与Update Q AC代码 总结与拓展 题面 题目链接 P2486 ...
- 洛谷 P2486 [SDOI2011]染色/bzoj 2243: [SDOI2011]染色 解题报告
[SDOI2011]染色 题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同 ...
- luogu题解P2486[SDOI2011]染色--树链剖分+trick
题目链接 https://www.luogu.org/problemnew/show/P2486 分析 看上去又是一道强行把序列上问题搬运到树上的裸题,然而分析之后发现并不然... 首先我们考虑如何在 ...
- P2486 [SDOI2011]染色(树剖)区间覆盖+区间的连续段
https://www.luogu.org/problemnew/show/P2486 值的一看https://www.cnblogs.com/Tony-Double-Sky/p/9283262.ht ...
- P2486 [SDOI2011]染色 维护区间块数 树链剖分
https://www.luogu.org/problemnew/show/P2486 题意 对一个树上维护两种操作,一种是把x到y间的点都染成c色,另一种是求x到y间的点有多少个颜色块,比如11 ...
- 洛谷P2486 [SDOI2011]染色 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2486 首先这是一道树链剖分+线段树的题. 线段树部分和 codedecision P1112 区间连续段 一模一样,所以我们 ...
随机推荐
- python对缩进的严格要求
一般的编辑器都会默认Tab键为四格缩进,但是在python脚本中,Tab与直接4个tablespace空格是有区别的. 一般表现为报错信息如下: IndentationError: unindent ...
- Python全栈-异常处理
一.异常 1.异常的定义 异常是错误发生的信号,程序一旦出错就会抛出错误信息,如果不及时处理就会程序就会随之停止运行 异常有三部分组成: 1)异常类型 2)异常追踪 3)异常的值 2.异常的分类 1) ...
- UML之组件图
基本概念:组件图即是用来描述组件与组件之间关系的一种UML图.组件图在宏观层面上显示了构成系统某一个特定方面的实现结构. 组件图中主要包含三种元素,即组件.接口和关系. 组件图通过这些元素描述了系统的 ...
- Block 循环引用(中)
不会造成循环引用的block 大部分GCD方法 dispatch_async(dispatch_get_main_queue(), ^{ [self doSomething]; }); 因为self并 ...
- Swift 了解(2)
循环(Loops) 1. For条件递增语句 ; counter < ; counter++ ) { liftWeights( ) } 语法是这样的:用for作为循环的开始,告诉Xcode你要声 ...
- 在lua中从一个字符串中移除空间源码
/* trim.c - based on http://lua-users.org/lists/lua-l/2009-12/msg00951.html from Sean Conner */ #inc ...
- Class__One HomeWork 实验报告
石家庄铁道大学信息科学与技术学院 实验报告 2018年----2019年 第一学期 题目: 四则运算和验证码 课程名称: JAVA语言程序设计 班 ...
- 20165215 2017-2018-2 《Java程序设计》第6周学习总结
20165215 2017-2018-2 <Java程序设计>第6周学习总结 教材学习内容总结 chapter8 Java把String类定义为final类,即String类不能有子类 用 ...
- golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web
golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web Nginx 部署 - beego: 简约 & 强大并存的 Go 应用框架https://bee ...
- bootsrtap h5 移动版页面 在苹果手机ios滑动上下拉动滚动卡顿问题解决方法
bootsrtap h5 移动版页面 在苹果手机ios滑动上下拉动滚动卡顿问题解决方法 bootsrtap框架做的h5页面,在android手机下没有卡顿问题,在苹果手机就一直存在这问题,开始毫无头绪 ...