分析

[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. Go语言入门篇-项目常见用法&语法

    一.导入包用法: //_表示仅执行该包下的init函数(不需要整个包导入) import _ "git.xx.xx/baases/identity/cachain/version" ...

  2. 更新代码 出现 You need to upgrade the working copy first 错误

    今天更新了Eclipse的subclipse插件,更新代码报如下错误: svn: The working copy at 'E:\591woospace\kst_fashion_alipay_v1.2 ...

  3. [转帖]Docker从入门到动手实践

    Docker从入门到动手实践 https://www.cnblogs.com/nsky/p/10853194.html dockerfile的图很好呢. 但是自己没有做实验 , 其实知识都挺好. do ...

  4. C++ 14 auto

    C++14标准最近刚被通过,像以前一样,没有给这个语言带来太大变化,C++14标准是想通过改进C++11 来让程序员更加轻松的编程,C++11引入auto关键字(严格来说auto从C++ 03 开始就 ...

  5. 图——图的Kruskal法最小生成树实现

    1,最小生成树的特征: 1,选取的边是图中权值较小的边: 2,所有边连接后不构成回路: 2,prim 算法是以顶点为核心的,最下生成树最大的特征是边,但 prim 算法非要以顶点为核心来进行,有些复杂 ...

  6. [2019多校联考(Round 6 T3)]脱单计划 (费用流)

    [2019多校联考(Round 6 T3)]脱单计划 (费用流) 题面 你是一家相亲机构的策划总监,在一次相亲活动中,有 n 个小区的若干男士和 n个小区的若干女士报名了这次活动,你需要将这些参与者两 ...

  7. Spring aop 实例(转)

    面向切面编程,有效的降低了代码之间的耦合性,易于维护:例如:我们习惯在代码中加上一些日志信息,在程序出错时方便快速查找找到问题,通常做法是在请求进入方法的时候打印日志,退出前打印日志,还有在出错时打印 ...

  8. J.U.C|一文搞懂AQS(转)

    提到JAVA加锁,我们通常会想到synchronized关键字或者是Java Concurrent Util(后面简称JCU)包下面的Lock,今天就来扒一扒Lock是如何实现的,比如我们可以先提出一 ...

  9. C语言双向链表讲解

    一.双向链表的概念 双向链表基于单链表.单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行.而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点 ...

  10. tomcat下的日志配置详细说明

    #可配置项(5类日志):catalina.localhost.manager.admin.host-manager handlers = 1catalina.org.apache.juli.FileH ...