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 区间连续段 一模一样,所以我们 ...
随机推荐
- Other Problems
http://www.cnblogs.com/coder211/p/7919749.html http://blog.jobbole.com/17763/http://www.open-open.co ...
- report源码分析——report_handle和report_server和report_catcher
report_handle主要实现对message的action,severity,file的设置,然后将message传递给server: 主要的function有两个:initial和proces ...
- Solid Dominoes Tilings (轮廓线dp打表 + 容器)
第一步先打一个表,就是利用轮廓线DP去打一个没有管有没有分界线组合数量的表 #include<bits/stdc++.h> using namespace std; ; <<; ...
- C#基础知识整理
年时,北风吹雁雪纷纷,一条秋裤冻上头.冷的连手都懒得动,就随便翻翻书,也没有更新博客,如今年已过,开始投入到正常的工作状态中,趁现在需求还没有来,把C#基础知识梳理一下,其实一直以来就想这样做的,对于 ...
- webservice 生成客户端代码
使用 jdk 自带工具 wsimport wsimport -keep http://webservice/url?wsdl
- 前端规范--eslint standard
https://github.com/standard/standard/blob/master/docs/RULES-zhcn.md
- Linux服务器配置---安装nfs
安装nfs NFS是Network File System的缩写,即网络文件系统.客户端通过挂载的方式将NFS服务器端共享的数据目录挂载到本地目录下. 由于NFS支持的功能很多,不同功能会使用不同程序 ...
- vuejs-devtools浏览器调试chrome插件
vuejs-devtools浏览器调试chrome插件(360极速浏览器也可以安装,需要FQ)https://chrome.google.com/webstore/detail/vuejs-devto ...
- centos-ftp搭建
参照https://blog.csdn.net/a735834365/article/details/80622105 https://blog.csdn.net/a735834365/article ...
- rgferg
dfgsdfg fdvgdsafg fgdfgdfg