[BZOJ4817][SDOI2017]树点涂色:Link-Cut Tree+线段树
分析
与[BZOJ3779]重组病毒唯一的区别是多了一个链上求实链段数的操作。
因为每条实链的颜色必然不相同且一条实链上不会有两个深度相同的点(好像算法的正确性和第二个条件没什么关系,算了算了),画图分析可得,如果用\(dis[x]\)表示从\(x\)到根结点路径上的实链段数,则\(x\)到\(y\)路径上的实链段数可以表示为:
\]
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
using std::cin;
using std::cout;
using std::endl;
typedef long long LL;
inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
const int MAXN=100005;
int n,m;
int ecnt,head[MAXN];
int fa[MAXN],dep[MAXN],siz[MAXN],pc[MAXN];
int top[MAXN],id[MAXN],num[MAXN],tot;
int maxn[MAXN<<2],atag[MAXN<<2],loc,ql,qr,kk;
int sta[MAXN],statop;
struct Edge{
int to,nxt;
}e[MAXN<<1];
inline void add_edge(int bg,int ed){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
struct lct{
int fa,ch[2];
int tag;
}a[MAXN];
inline void subupd(int x,int kkk);
inline int subquery(int x);
#define lc a[x].ch[0]
#define rc a[x].ch[1]
inline bool isroot(int x){
return a[a[x].fa].ch[0]!=x&&a[a[x].fa].ch[1]!=x;
}
inline void pushr(int x){
std::swap(lc,rc);
a[x].tag^=1;
}
inline void pushdown(int x){
if(!a[x].tag) return;
if(lc) pushr(lc);
if(rc) pushr(rc);
a[x].tag=0;
}
inline void rotate(int x){
int y=a[x].fa,z=a[y].fa;
int f=(a[y].ch[1]==x),g=a[x].ch[f^1];
if(!isroot(y)) a[z].ch[a[z].ch[1]==y]=x;
a[x].ch[f^1]=y;
a[y].ch[f]=g;
if(g) a[g].fa=y;
a[y].fa=x;
a[x].fa=z;
}
inline void splay(int x){
int y=x,z;
statop=1;
sta[1]=y;
while(!isroot(y)) sta[++statop]=y=a[y].fa;
while(statop) pushdown(sta[statop--]);
while(!isroot(x)){
y=a[x].fa,z=a[y].fa;
if(!isroot(y)){
if((a[y].ch[0]==x)==(a[z].ch[0]==y)) rotate(y);
else rotate(x);
}
rotate(x);
}
}
inline int findroot(int x){
while(pushdown(x),lc) x=lc;
return x;
}
inline void access(int x){
for(int y=0;x;x=a[y=x].fa){
splay(x);
if(rc) subupd(findroot(rc),1);
rc=y;
if(rc) subupd(findroot(rc),-1);
}
}
#undef lc
#undef rc
void dfs1(int x,int pre,int depth){
fa[x]=pre;
a[x].fa=pre;
dep[x]=depth;
siz[x]=1;
int maxsiz=-1;
trav(i,x){
int ver=e[i].to;
if(ver==pre) continue;
dfs1(ver,x,depth+1);
siz[x]+=siz[ver];
if(siz[ver]>maxsiz){
maxsiz=siz[ver];
pc[x]=ver;
}
}
}
void dfs2(int x,int topf){
top[x]=topf;
id[x]=++tot;
num[tot]=x;
if(!pc[x]) return;
dfs2(pc[x],topf);
trav(i,x){
int ver=e[i].to;
if(ver==fa[x]||ver==pc[x]) continue;
dfs2(ver,ver);
}
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void build(int o,int l,int r){
if(l==r){
maxn[o]=dep[num[l]];
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
maxn[o]=std::max(maxn[lc],maxn[rc]);
}
inline void segpushdown(int o){
if(!atag[o]) return;
maxn[lc]+=atag[o];
maxn[rc]+=atag[o];
atag[lc]+=atag[o];
atag[rc]+=atag[o];
atag[o]=0;
}
void upd(int o,int l,int r){
if(ql<=l&&r<=qr){
maxn[o]+=kk;
atag[o]+=kk;
return;
}
segpushdown(o);
if(mid>=ql) upd(lc,l,mid);
if(mid<qr) upd(rc,mid+1,r);
maxn[o]=std::max(maxn[lc],maxn[rc]);
}
int squery(int o,int l,int r){
if(l==r) return maxn[o];
segpushdown(o);
if(loc<=mid) return squery(lc,l,mid);
else return squery(rc,mid+1,r);
}
int rquery(int o,int l,int r){
if(ql<=l&&r<=qr) return maxn[o];
segpushdown(o);
int ret=0;
if(mid>=ql) ret=std::max(ret,rquery(lc,l,mid));
if(mid<qr) ret=std::max(ret,rquery(rc,mid+1,r));
return ret;
}
#undef mid
#undef lc
#undef rc
inline int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
inline void subupd(int x,int kkk){
ql=id[x],qr=id[x]+siz[x]-1,kk=kkk;
upd(1,1,n);
}
inline int subquery(int x){
ql=id[x],qr=id[x]+siz[x]-1;
return rquery(1,1,n);
}
int main(){
n=read(),m=read();
rin(i,2,n){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
while(m--){
int opt=read();
if(opt==1){
int x=read();
access(x);
}
else if(opt==2){
int ans=0;
int x=read(),y=read();
loc=id[x];ans+=squery(1,1,n);
loc=id[y];ans+=squery(1,1,n);
loc=id[lca(x,y)];ans-=(squery(1,1,n)<<1);
ans++;
printf("%d\n",ans);
}
else{
int x=read();
printf("%d\n",subquery(x));
}
}
return 0;
}
[BZOJ4817][SDOI2017]树点涂色:Link-Cut Tree+线段树的更多相关文章
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
[BZOJ4817]树点涂色(LCT,线段树,树链剖分) 题面 BZOJ Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义 ...
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 692 Solved: 408[Submit][Status ...
- P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA
\(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...
- bzoj4817/luogu3703 树点涂色 (LCT+dfs序+线段树)
我们发现,这个染色的操作他就很像LCT中access的操作(为什么??),然后就自然而然地想到,其实一个某条路径上的颜色数量,就是我们做一个只有access操作的LCT,这条路径经过的splay的数量 ...
- BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)
题目链接 操作\(1.2\)裸树剖,但是操作\(3\)每个点的答案\(val\)很不好维护.. 如果我们把同种颜色的点划分到同一连通块中,那么向根染色的过程就是Access()! 最初所有点间都是虚边 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- Link Cut Tree 动态树 小结
动态树有些类似 树链剖分+并查集 的思想,是用splay维护的 lct的根是动态的,"轻重链"也是动态的,所以并没有真正的轻重链 动态树的操作核心是把你要把 修改/询问/... 等 ...
- LCT(link cut tree) 动态树
模板参考:https://blog.csdn.net/saramanda/article/details/55253627 综合各位大大博客后整理的模板: #include<iostream&g ...
- 洛谷.3690.[模板]Link Cut Tree(动态树)
题目链接 LCT(良心总结) #include <cstdio> #include <cctype> #include <algorithm> #define gc ...
随机推荐
- webpack初体验之模块化开发
写在前面的话 上次写过一篇关于webpack入门的博客,当时只是说借助node来完成开发,并用webpack打包以让浏览器识别.其实其主要思想就是实现前端模块化开发. 众所周知,历史上,JavaScr ...
- 悼念512汶川大地震遇难同胞——选拔志愿者 HDU 2188 博弈论 巴什博奕
悼念512汶川大地震遇难同胞--选拔志愿者 HDU 2188 博弈论 巴什博奕 题意 对于四川同胞遭受的灾难,全国人民纷纷伸出援助之手,几乎每个省市都派出了大量的救援人员,这其中包括抢险救灾的武警部队 ...
- FHJ学长的心愿 QDUOJ 数论
FHJ学长的心愿 原题链接,点我进去 题意 给你一个数N,让你求在\[C^{0}_{n} \ C^{1}_{n}\ C^{2}_{n}\ \dots \ C^{n}_{n}\]中有几个组合数是奇数. ...
- 洛谷 P1484 种树(优先队列,贪心,链表)
传送门 解题思路 第一眼的贪心策略:每次都选最大的. 但是——不正确! 因为选了第i个树,第i-1和i-1棵树就不能选了.所以,要有一个反悔操作. 选了第i个后,我们就把a[i]的值更新为a[l[i] ...
- centos6配置本地yum源
在无法访问外网时,yum安装软件会失败,这时候可以配置yum源为本地的镜像iso来解决这个问题 1. 使用Xftp上传iso镜像文件到服务器 2. 使用如下命令新建挂载点并挂载 sudo mkdir ...
- D-多连块拼图
多连块是指由多个等大正方形边与边连接而成的平面连通图形. – 维基百科 给一个大多连块和小多连块,你的任务是判断大多连块是否可以由两个这样的小多连块拼成.小多连块只能平移,不能旋转或者翻转.两个小多连 ...
- vmware下使用nat方法联网
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/Li_Zefeng/article/det ...
- 动态规划(股票交易)---只能进行 k 次的股票交易
只能进行 k 次的股票交易 188. Best Time to Buy and Sell Stock IV (Hard) 题目描述: 只能进行K次股票交易,求能获得的最大利润 思路分析: 和只 ...
- DataTable中如何去除重复的项 (获得某个字段中的不重复项)
就是获取DataTable中某一列的值,因为从数据库中检索数据时,按照2个字段进行分组,而要获得的那一列刚好在分组这两列中,所以该列的值必然有重复,于是就想到了去除重复,有了思路以后在网上看了一些方法 ...
- npm学习(十三)之npm命令
npm:查看npm所有命令 自己写包可能用到的命令: npm adduser:注册 npm login:登录 npm whami:查看当前用户名 npm init:初始化包的信息 npm publis ...