分析

[BZOJ3779]重组病毒唯一的区别是多了一个链上求实链段数的操作。

因为每条实链的颜色必然不相同且一条实链上不会有两个深度相同的点(好像算法的正确性和第二个条件没什么关系,算了算了),画图分析可得,如果用\(dis[x]\)表示从\(x\)到根结点路径上的实链段数,则\(x\)到\(y\)路径上的实链段数可以表示为:

\[dis[x]+dis[y]-dis[lca(x,y)]*2+1
\]

代码

#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+线段树的更多相关文章

  1. 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)

    [BZOJ4817]树点涂色(LCT,线段树,树链剖分) 题面 BZOJ Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义 ...

  2. [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 692  Solved: 408[Submit][Status ...

  3. P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA

    \(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...

  4. bzoj4817/luogu3703 树点涂色 (LCT+dfs序+线段树)

    我们发现,这个染色的操作他就很像LCT中access的操作(为什么??),然后就自然而然地想到,其实一个某条路径上的颜色数量,就是我们做一个只有access操作的LCT,这条路径经过的splay的数量 ...

  5. BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)

    题目链接 操作\(1.2\)裸树剖,但是操作\(3\)每个点的答案\(val\)很不好维护.. 如果我们把同种颜色的点划分到同一连通块中,那么向根染色的过程就是Access()! 最初所有点间都是虚边 ...

  6. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  7. Link Cut Tree 动态树 小结

    动态树有些类似 树链剖分+并查集 的思想,是用splay维护的 lct的根是动态的,"轻重链"也是动态的,所以并没有真正的轻重链 动态树的操作核心是把你要把 修改/询问/... 等 ...

  8. LCT(link cut tree) 动态树

    模板参考:https://blog.csdn.net/saramanda/article/details/55253627 综合各位大大博客后整理的模板: #include<iostream&g ...

  9. 洛谷.3690.[模板]Link Cut Tree(动态树)

    题目链接 LCT(良心总结) #include <cstdio> #include <cctype> #include <algorithm> #define gc ...

随机推荐

  1. Linux 自学shell

    1.多个命令用";"分号分割 还可以使用alias 给命令取别名 alias foo='cd /usr ; ls; cd -'2.使用管道线"|" 一个命令的标 ...

  2. Centos中使用Docker部署Apollo

    采用微服务开发框架开发项目时会涉及多个系统,如果要更改配置参数需要在多个系统间逐一更改,比较费时,而且容易遗漏,效率低下,次问题可以采用Apollo配置中心的方式解决,下面将介绍如何配置: 准备环境: ...

  3. HNUSTOJ-1639 分糖果(几何)

    1639: 分糖果 时间限制: 1 Sec  内存限制: 128 MB提交: 261  解决: 118[提交][状态][讨论版] 题目描述 为了实验室的发展,吴大大采购了一箱零食O(∩_∩)O~~ 在 ...

  4. NoSQL特点

  5. 计算机系统结构总结_Memory Review

    这次就边学边总结吧,不等到最后啦 Textbook: <计算机组成与设计——硬件/软件接口>  HI <计算机体系结构——量化研究方法>       QR Ch3. Memor ...

  6. 解决stanfordnlp一直运行不报错也没有结果

    最近学习stanfordnlp,当运行程序时,发现程序一直没有反应,上网查询说是内存不够,但是本地电脑是8g内存.后来重新下载了所需文件,问题解决.

  7. 搬家至csdn

    搬家至csdn https://blog.csdn.net/qq_42866164

  8. Spring基础16——使用FactoryBean来创建

    1.配置bean的方式 配置bean有三种方式:通过全类名(class反射).通过工厂方法(静态工厂&实例工厂).通过FactoryBean.前面我们已经一起学习过全类名方式和工厂方法方式,下 ...

  9. /etc/nscd.conf - 域名服务缓存守护进程配置文件

    描述 DESCRIPTION 该文件 /etc/nscd.conf 在启动 nscd(8) 时读入.每一行或者指定一个属性和值,或者指定一个属性.服务和一个值.域之间通过空格或者TAB分开.‘#’表示 ...

  10. 一、ASP.NET Iframework_SignalR永久连接类(v2)

    一.新建项目,选MVC项目默认 添加mvc文件夹和核心引用 二.添加SignaIR包 SignalR的准备:NuGet包管理器搜索:工具——>库程序包管理器——>Microsoft.Asp ...