bzoj4817/luogu3703 树点涂色 (LCT+dfs序+线段树)
我们发现,这个染色的操作他就很像LCT中access的操作(为什么??),然后就自然而然地想到,其实一个某条路径上的颜色数量,就是我们做一个只有access操作的LCT,这条路径经过的splay的数量
然后考虑怎么样来维护这个数量。access的过程中,有实边变虚边、虚边变实边的操作,对应过来,实边变虚边,就是以(断掉的那个子splay树中的在原树中最浅的点)为根的子树中 每个点到根的颜色数++(多拆出来了一个splay嘛),虚边变实边同理,不过是--
这样就可以再用一个线段树维护dfs序了,第三个询问就是线段树上的最大值
第二个询问,如果有x,y,lca,那x到y路径上的颜色数就是num[x]+num[y]-2*num[lca]+1,num[i]就是刚才线段树记的那个
#include<bits/stdc++.h>
#define pa pair<int,int>
#define CLR(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e5+; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} int N,M;
int eg[maxn*][],egh[maxn],ect;
int dep[maxn],dfn[maxn][],fa[maxn],ch[maxn][],tot;
int bf[maxn][],ma[maxn*],laz[maxn*],id[maxn]; inline void adeg(int a,int b){
eg[++ect][]=b,eg[ect][]=egh[a];egh[a]=ect;
} void dfs(int x){
dfn[x][]=++tot;id[tot]=x;
for(int i=;bf[x][i]&&bf[bf[x][i]][i];i++)
bf[x][i+]=bf[bf[x][i]][i];
for(int i=egh[x];i;i=eg[i][]){
int b=eg[i][];
if(b==fa[x]) continue;
fa[b]=bf[b][]=x;dep[b]=dep[x]+;
dfs(b);
}
dfn[x][]=tot;
} inline int getlca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=log2(dep[x]-dep[y]);i>=&&dep[x]!=dep[y];i--){
if(dep[bf[x][i]]>=dep[y])
x=bf[x][i];
}
if(x==y) return x;
for(int i=log2(dep[x]);i>=;i--){
if(bf[x][i]!=bf[y][i])
x=bf[x][i],y=bf[y][i];
}
return bf[x][];
} inline bool nroot(int x){return x==ch[fa[x]][]||x==ch[fa[x]][];}
inline bool isrt(int x){return x==ch[fa[x]][];} inline void rotate(int x){
int f=fa[x],ff=fa[fa[x]];bool b=isrt(x);
fa[x]=ff;if(nroot(f)) ch[ff][isrt(f)]=x;
fa[ch[x][!b]]=f,ch[f][b]=ch[x][!b];
fa[f]=x,ch[x][!b]=f;
} inline void splay(int x){
while(nroot(x)&&nroot(fa[x])){
if(isrt(x)==isrt(fa[x])) rotate(fa[x]);
else rotate(x);rotate(x);
}if(nroot(x)) rotate(x);
} inline int getl(int x){
while(ch[x][]) x=ch[x][];
return x;
} inline void update(int p){ma[p]=max(ma[p<<],ma[p<<|]);}
inline void pushdown(int p){
if(!laz[p]) return;
int a=p<<,b=p<<|;
laz[a]+=laz[p],laz[b]+=laz[p];
ma[a]+=laz[p],ma[b]+=laz[p];
laz[p]=;
} inline void build(int p,int l,int r){
if(l==r) ma[p]=dep[id[l]];
else{
int m=l+r>>;
build(p<<,l,m);
build(p<<|,m+,r);
update(p);
}
}
inline void add(int p,int l,int r,int x,int y,int z){
// printf("%d %d %d %d %d\n",p,l,r,x,y);
if(x<=l&&r<=y){
ma[p]+=z;laz[p]+=z;
}else{
pushdown(p);
int m=l+r>>;
if(x<=m) add(p<<,l,m,x,y,z);
if(y>=m+) add(p<<|,m+,r,x,y,z);
update(p);
}
}
inline int query(int p,int l,int r,int x,int y){
if(!x||!y) return ;
if(x<=l&&r<=y) return ma[p];
pushdown(p);
int m=l+r>>,re=;
if(x<=m) re=query(p<<,l,m,x,y);
if(y>=m+) re=max(re,query(p<<|,m+,r,x,y));
return re;
} inline void access(int x){
for(int y=;x;y=x,x=fa[x]){
splay(x);
int a=getl(ch[x][]),b=getl(y);
// printf("!%d %d\n",a,b);
if(a) add(,,N,dfn[a][],dfn[a][],);
if(b) add(,,N,dfn[b][],dfn[b][],-);
ch[x][]=y;
}
} inline int gettop(int x){
while(nroot(x)) x=fa[x];
return x;
} int main(){
//freopen("","r",stdin);
int i,j,k;
N=rd(),M=rd();
for(i=;i<N;i++){
int a=rd(),b=rd();
adeg(a,b);adeg(b,a);
}
dep[]=;dfs();
build(,,N);
for(i=;i<=M;i++){
int a=rd(),x=rd();
if(a==) access(x);
else if(a==){
int y=rd();
int lca=getlca(x,y);
// printf("%d %d\n",x,y)
printf("%d\n",query(,,N,dfn[x][],dfn[x][])+
query(,,N,dfn[y][],dfn[y][])-
*query(,,N,dfn[lca][],dfn[lca][])+);
}else{
printf("%d\n",query(,,N,dfn[x][],dfn[x][]));
}
}
return ;
}
bzoj4817/luogu3703 树点涂色 (LCT+dfs序+线段树)的更多相关文章
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 692 Solved: 408[Submit][Status ...
- BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)
题目链接 操作\(1.2\)裸树剖,但是操作\(3\)每个点的答案\(val\)很不好维护.. 如果我们把同种颜色的点划分到同一连通块中,那么向根染色的过程就是Access()! 最初所有点间都是虚边 ...
- P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA
\(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...
- [BZOJ3779]重组病毒(LCT+DFS序线段树)
同[BZOJ4817]树点涂色,只是多了换根操作,分类讨论下即可. #include<cstdio> #include<algorithm> #define lc ch[x][ ...
- [BZOJ4817][SDOI2017]树点涂色:Link-Cut Tree+线段树
分析 与[BZOJ3779]重组病毒唯一的区别是多了一个链上求实链段数的操作. 因为每条实链的颜色必然不相同且一条实链上不会有两个深度相同的点(好像算法的正确性和第二个条件没什么关系,算了算了),画图 ...
- BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...
- Educational Codeforces Round 6 E dfs序+线段树
题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...
- 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心
3252: 攻略 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 339 Solved: 130[Submit][Status][Discuss] D ...
- Codeforces 343D Water Tree(DFS序 + 线段树)
题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...
随机推荐
- 机器学习(三)--- scala学习笔记
Scala是一门多范式的编程语言,一种类似Java的编程语言,设计初衷是实现可伸缩的语言.并集成面向对象编程和函数式编程的各种特性. Spark是UC Berkeley AMP lab所开源的类Had ...
- 【强化学习】python 实现 q-learning 例四(例二改写)
将例二改写成面向对象模式,并加了环境! 不过更新环境的过程中,用到了清屏命令,play()的时候,会有点问题.learn()的时候可以勉强看到:P 0.效果图 1.完整代码 相对于例一,修改的地方: ...
- Spring Cloud 入门教程(十):和RabbitMQ的整合 -- 消息总线Spring Cloud Netflix Bus
在本教程第三讲Spring Cloud 入门教程(三): 配置自动刷新中,通过POST方式向客户端发送/refresh请求, 可以让客户端获取到配置的最新变化.但试想一下, 在分布式系统中,如果存在很 ...
- JQuery_自带的动画效果
1.方法: show:显示选中元素. hide:隐藏选中元素. toggle:显示或隐藏选中元素. fadeIn:将选中元素的不透明度逐步提升到100%. fadeOut:将选中元素的不透明度逐步降为 ...
- C#_面试
class Program { static void Main(string[] args) { , , , , }; var arry = ConvertSum(arr); , , , , , } ...
- Linux下性能调试工具运维笔记
作为一名资深的linux运维工程师,为方便了解和追求服务器的高性能,如cpu.内存.io.网络等等使用情况,要求运维工程师必须要熟练运用一些必要的系统性能调试工具,liunx下提供了众多命令方便查看各 ...
- 撰写POPUSH需求文档
不当家不知柴米贵,撰写了正规的软件需求文档才知道软件工程的复杂性 感谢@洪宇@王需@江林楠下午的加班加点,五个人正闷在406B奋斗中,加油!
- <<梦断代码>>阅读笔记一
没有想象中的枯燥,甚至有些有趣.这就是我对<梦断代码>这一本书的第一印象.而且,作为一本面向程序员的书籍,作者很有意义地从第0章开始,那我也从第0章开始说.这第一次读书笔记是针对0~2 章 ...
- cglib 动态代理
JDK的动态代理比较慢,可以使用cglib的代理,速度比较快: package cn.demo02; import java.lang.reflect.Method; import java.util ...
- SDN网络虚拟化、资源映射等相关论文粗读
1. Control Plane Latency with SDN Network Hypervisors: The Cost of Virtualization 年份:2016 来源:IEEE NE ...