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序+线段树了.而对于第二个操作,考虑再维护一 ...
随机推荐
- STM32 M3内核的位带操作原理及步骤
STM32 M3内核的位带操作原理及步骤 一.位带操作有什么用?什么是位带操作 位带操作的作用:可以实现对某一GPIO口寄存器(或SRAM内存中)的某一bit位直接写0或1,达到控制GPIO口输出(或 ...
- Jlink使用技巧之烧写SPI Flash存储芯片
前言 大多数玩单片机的人都知道Jlink可以烧写Hex文件,作为ARM仿真调试器,但是知道能烧写SPI Flash的人应该不多,本篇文章将介绍如何使用JLink来烧写或者读取SPI Flash存储器, ...
- [HNOI2018]排列[堆]
题意 给定一棵树,每个点有点权,第 \(i\) 个点被删除的代价为 \(w_{p[i]}\times i\) ,问最小代价是多少. 分析 与国王游戏一题类似. 容易发现权值最小的点在其父亲选择后就会立 ...
- ASP.NETZERO 开发者指南-目录篇
前面的话 此教程适用于 ASP.NET MVC 5.x & Angularjs 1.x 的ABP框架(收费需要授权) 所以有能力的朋友还是希望你们多多支持 土牛.购买链接:https://w ...
- Week7阅读笔记
关于银弹: Brooks在他最著名的这篇文章里指出,在软件开发过程里是没有万能的终杀性武器的,只有各种方法综合运用,才是解决之道.而各种声称如何如何神奇的理论或方法,都不是能杀死“软件危机”这头人狼的 ...
- NoSuchBeanDefinitionException:No qualifying bean of type
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException ...
- PAT 1011 A+B和C
https://pintia.cn/problem-sets/994805260223102976/problems/994805312417021952 给定区间[-2^31^, 2^31^]内的3 ...
- JQuery Cross Domain Ajax(jsonp)
http://www.pureexample.com/jquery/cross-domain-ajax.html http://www.pureexample.com/ExampleTesterII- ...
- Oracle18c OnlyExadataVersion 安装说明
1.根据惜分飞还有盖国强老师云和恩墨的文章, 验证了下OnlyExadataVersion的Oracle18c的数据库安装过程. 2.oracle参数修改以及创建用户, 目录, 修改.bash_pro ...
- Cmder 常用配置
windows 系统的 cmd 命令窗口不是很好用,可以试试 Cmder 工具包. 1.在运行框中快速启动 Cmder 将 cmder.exe 文件所在目录加载环境变量 PATH 中. 2.把 cms ...