[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 ...
随机推荐
- 避免浏览器缓存JS
有时候更改了JS代码,但是浏览器内容不变,这样<script src="Scripts/myjs/Master.js?v"></script>引入JS就可以 ...
- 循环Gray码的生成(递归)
#!/usr/bin/env python #coding:utf-8 import sys def gray_code(num, array): if num < 1: return if n ...
- 自动构建War包的Ant build.xml模板
<?xml version="1.0" encoding="UTF-8" ?> <project name="[*****]你的项目 ...
- Node.js连接RabbitMQ,断线重连,动态绑定routing key
RabbitMQ官方提供的教程https://www.rabbitmq.com/tuto...,是基于回调的. 下面将给出基于Promise式的写法.并且实现动态的队列绑定 初始化配置 const a ...
- 高性能迷你React框架anujs1.1.3发布
anujs现在只差一个组件(mention)就完全支持阿里的antd UI库了.一共跑通346个测试, 应该是全世界最接近官方React的迷你框架了. 以后的工作就是把React16的一些新特性支持了 ...
- Zookeeper入门概要
ZooKeeper是一个开源的分布式协调服务,由雅虎创建,是Google Chubby的开源实现.ZooKeeper的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集 ...
- styled-components缺点
缺点 不能用 stylelint 检查你的 Css 代码 在使用 styled-components 的过程中也会遇到一些问题,比如我们的项目会用stylelint来做样式代码的检查,但是使用了 st ...
- iOS开发之详解剪贴板
关于UIMenuController的用法例子 今天终于搞明白了UIMenuController显示的相关内容,把源代码分享给大家! 要正常显示菜单,必须做到以下几点:1. -(BOOL)canBec ...
- SSM框架返回json数据
常见错误:No converter found for return value of type: class .................. 原因分析:这是因为springmvc默认是没有对象 ...
- 动态路由协议RIP
RIP Routing Information Protocol,属IGP协议,是距离矢量型动态路由协议(直接发送路由信息的协议为距离矢量型协议),使用UDP协议,端口号520. 贝尔曼福特算法 RI ...