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 区间连续段 一模一样,所以我们 ...
随机推荐
- linux中使用另一用户打开拥有图形界面的程序
在archlinux中使用oracle用户执行oui无法显示图形界面的问题.结果没解决,后来发现执行 xhost +si:localuser:oracle, 然后再使用oracle用户执行oui即可. ...
- 标准I/O流
一.标准输入流 标准输入流对象cin,重点掌握的函数 cin.get() //一次只能读取一个字符 cin.get(一个参数) //读一个字符 cin.get(三个参数) //可以读字符串 cin.g ...
- os.system
python os.system os.system()函数在不同的系统下可以实现不同的作用 一.window下: os.system("ping www.baidu.com" ...
- 从网站上扒网页,保存为file文件格式
保存下来的页面总是有部分特效缺失,可是文件包里已经有好几个js文件了. 例如想保存易迅的搜索页面,条件筛选栏的按钮全部失效了,按钮-更多.多选等 都没有反应,搜索结果的鼠标悬浮显示完整信息也没有了. ...
- hi3516a arm-hisiv300-linux-gcc jrtplib交叉编译
1.进入JThread-1.2.1文件夹 2../configure --prefix=/home/suxuandong/Documents/qth264/hi3516/jrtpjthreadhisi ...
- flask上下文全局变量,程序上下文、请求上下文、上下文钩子
Flask上下文 Flask中有两种上下文,程序上下文(application context)和请求上下文(request context) 当客户端发来请求时,请求上下文就登场了.请求上下文里包含 ...
- SpringMVC七种参数绑定简单介绍
a. 默认支持的类型: httpServletRequest, httpservletresponse, httpsession, model 看自己需要, 如果需要用就加 ...
- vue-i18n国际化插件
vue-i18n国际化插件 安装,到项目目录下执行:npm install vue-i18n 配置在src\main.js里面引入vue-i18n // 语言包插件import VueI18n fro ...
- VPS高性能虚拟机KVM详解
1. KVM 介绍 1.0 虚拟化简史 其中,KVM 全称是 基于内核的虚拟机(Kernel-based Virtual Machine),它是Linux 的一个内核模块,该内核模块使得 Linux ...
- NFS客户端阻塞睡眠问题与配置调研
Linux NFS客户端需要很小心地配置,否则在NFS服务器崩溃时,访问NFS的程序会被挂起,用ps查看,进程状态(STAT)处于D,意为(由于IO阻塞而进入)不可中断睡眠(如果是D+,+号表示程序运 ...