洛谷题目传送门

闲话

这是所有LCT题目中的一个异类。

之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合。

只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要喧宾夺主了。。。(至少在代码上看是如此)

思路分析

一个一个操作来(瞎BB中,这种思路模式并不具有普遍性。。。。。。)

1操作

还好我没学树剖233333以至于(直接想到)只好用LCT来维护颜色。

题目透露出的神奇的性质——每一种颜色,无论在任何时刻,肯定是一条链,而且点的深度严格递增!

而且还特意指定根节点!1操作特意修改x到根节点的颜色!

想到了这里,就不难想到本题的关键模型——LCT中每个Splay辅助树维护同颜色点的集合

于是1操作==access。。。。。。

2操作

x到y路径?split?!

I'm too young too simple

LCT维护了集合,就只能维护集合了。随便再乱搞一下集合就被破坏了。

于是就要再外部维护了。

至于维护什么,现在其实还不能产生很好的思路。。。。。

但我们可以先想到一点:没有了LCT,还要资磁树中任意两点之间的询问?

常见的复杂度正确的方法(套路)能想到的就只有树上差分了吧(设F为状态,那么就形如F[x]+F[y]-F[lca])

于是就可以只维护每个点到根节点路径上的颜色种数

转化一下,在LCT中就等价于每个点到根节点路径所要经过的轻边总数,这里又是一个关键点

查询F[x]+F[y]-2F[lca]+1(+1是因为lca所在的颜色被减了两次)

不会树剖,只好写倍增LCA

然后就可以转而思考如何维护这个状态了

首先初始状态就是每个点的深度,然后就接着考虑修改了。

因为状态只与轻边有关,所以在access时更改就可以啦

可以类比一下LCT维护子树信息和(可参考一下Blog的LCT总结

access中有替换右儿子的操作,等于把原来一条边变轻,新的一条边变重

那么原来那条边所指的子树状态全部要+1(多了一个轻边),新连上的边所指的子树状态全部要-1

于是问题又出现了。。。

众所周知,LCT可以维护子树信息,但不可以修改子树信息

树剖很好维护就不提了,然后我又不会树剖TOT(我太弱了)

在这紧要关头,dfn序救了我。。。。。。

一个子树,所有的点的dfn序一定是连续的区间

所以维护线段树,表示dfn序的区间,修改的时候在对应的区间修改,查询就单点查

3操作

所有的思路难点,在操作2冗长的思路分析中都攻克了

这里就在线段树里维护状态最大值(树剖也一样),区间查询就好啦

至于写法,线段树里的区间加减法可以写懒标记,也可以实现永久化标记(YL巨佬做法,常数暴踩本蒟蒻,目前rank1)

只不过我试了一下,dfn序线段树写永久化标记因为某些无法描述的玄学问题变得更慢了。。。。。。

思路就这样,有些细节在代码里(Debug一晚上带来的惨痛的经验。。。。。。)

算上in,pup,pdn和main,此程序一共有15个函数。。。。。。

#include<cstdio>
#include<iostream>
using namespace std;
#define I inline
#define R register int
#define G ch=getchar()
#define in(z) G;\
while(ch<'-')G;\
z=ch&15;G;\
while(ch>'-')z*=10,z+=ch&15,G
#define lc x<<1
#define rc x<<1|1
#define pup mx[x]=max(mx[lc],mx[rc])
#define pdn if(lz[x])upd(lc,l[x],m[x],lz[x]),upd(rc,m[x]+1,r[x],lz[x]),lz[x]=0
//都是线段树操作,本题的LCT内部没有维护信息
const int N=100009,M=N*20;
int l[M],m[M],r[M],mx[M],lz[M],f[N],c[N][2],st[N][20],o[N];
int p=1,he[N],ne[N<<1],to[N<<1],d[N],dfn[N],at[N],mr[N],now;
//at是dfn的反表示,mr表示每个点的子树在dfn序区间中的右端点(左端点是它自己)
I void dfs(R x,R fa){//建树预处理
d[now=at[dfn[x]=++p]=x]=d[st[x][0]=f[x]=fa]+1;//一堆信息的预处理压进了一行
for(R&i=o[x];(st[x][i+1]=st[st[x][i]][i]);++i);//倍增LCA预处理
for(R i=he[x];i;i=ne[i])
if(fa!=to[i])dfs(to[i],x);
mr[x]=now;
}
I int lca(R x,R y){//求LCA
if(d[x]<d[y])swap(x,y);
for(R i=o[x];i>=0;--i)
if(d[st[x][i]]>=d[y])x=st[x][i];//Debug中的错误1:>=写成了>
if(x==y)return x;
for(R i=o[x];i>=0;--i)
if(st[x][i]!=st[y][i])x=st[x][i],y=st[y][i];
return st[x][0];
}
I void build(R x,R s,R e){//建线段树
l[x]=s;r[x]=e;m[x]=(s+e)>>1;
if(s==e){mx[x]=d[at[s]];return;}//利用反表示找到初始状态
build(lc,s,m[x]);build(rc,m[x]+1,e);pup;
}
I void upd(R x,R s,R e,R v){//区间修改
if(l[x]==s&&r[x]==e){mx[x]+=v;lz[x]+=v;return;}//注意mx也要变
pdn;
if(e<=m[x])upd(lc,s,e,v);
else if(s>m[x])upd(rc,s,e,v);
else upd(lc,s,m[x],v),upd(rc,m[x]+1,e,v);
pup;
}
I int get(R s){//单点查值,与区间查值分开了,为了减小常数
R x=1;
while(l[x]!=r[x]){
pdn;x=(lc)+(s>m[x]);
}
return mx[x];
}
I int ask(R x,R s,R e){//区间查值
if(l[x]==s&&r[x]==e)return mx[x];
pdn;
if(e<=m[x])return ask(lc,s,e);
if(s>m[x])return ask(rc,s,e);
return max(ask(lc,s,m[x]),ask(rc,m[x]+1,e));
}
I bool nrt(R x){//LCT部分
return c[f[x]][0]==x||c[f[x]][1]==x;
}
I void rot(R x){
R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nrt(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
f[w]=y;f[y]=x;f[x]=z;//Debug中的错误2:y写成了x
}
I void splay(R x){
R y;
while(nrt(x)){
if(nrt(y=f[x]))rot((c[f[y]][0]==y)^(c[y][0]==x)?x:y);
rot(x);
}
}
I int frt(R x){//有别于传统意义下的findroot
while(c[x][0])x=c[x][0];
return x;
}
I void access(R x){
for(R w,y=0;x;x=f[y=x]){
splay(x);
if(c[x][1])w=frt(c[x][1]),upd(1,dfn[w],dfn[mr[w]],1);
if((c[x][1]=y))w=frt(y),upd(1,dfn[w],dfn[mr[w]],-1);
//Debug中的错误3:这里更新要找原子树的根(即深度最小的那个点)
//而不能把辅助树的根当原子树根直接upd(1,dfn[c[x][1]],dfn[mr[c[x][1]]],1)
}
}
int main(){
register char ch;
R n,m,i,a,b,op,x,y;
in(n);in(m);
for(i=1;i<n;++i){
in(a);in(b);
to[++p]=b;ne[p]=he[a];he[a]=p;
to[++p]=a;ne[p]=he[b];he[b]=p;
}
p=0;dfs(1,0);build(1,1,n);
while(m--){
in(op);in(x);
if(op==1)access(x);
else if(op==2){
in(y);
printf("%d\n",get(dfn[x])+get(dfn[y])-get(dfn[lca(x,y)])*2+1);
}
else printf("%d\n",ask(1,dfn[x],dfn[mr[x]]));
}
return 0;
}

洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)的更多相关文章

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

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

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

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

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

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

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

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

  5. bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论

    题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...

  6. [BZOJ4817][SDOI2017]树点涂色:Link-Cut Tree+线段树

    分析 与[BZOJ3779]重组病毒唯一的区别是多了一个链上求实链段数的操作. 因为每条实链的颜色必然不相同且一条实链上不会有两个深度相同的点(好像算法的正确性和第二个条件没什么关系,算了算了),画图 ...

  7. [Sdoi2017]树点涂色 [lct 线段树]

    [Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...

  8. 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树

    [BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...

  9. 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

    树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...

随机推荐

  1. [SCOI2007]修车 BZOJ1070

    很久之前写的题了,今天翻出来写一篇博客复习一下... 分析: 考虑,T <= 1000,并不能针对这一维处理,所以考虑将,每个人拆点,之后,拆完之后表示,这个人第n-j+1个修k这辆车,也就是, ...

  2. 20155211 网络攻防技术 Exp08 Web基础

    20155211 网络攻防技术 Exp08 Web基础 实践内容 Web前端HTML,能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML. We ...

  3. 20155339 Exp7 网络欺诈防范

    20155339 Exp7 网络欺诈防范 .基础问题回答 (1)通常在什么场景下容易受到DNS spoof攻击 当连接局域网的时候应该最容易被攻击,比如说连接了一些不清楚是什么的WiFi其实是很容易收 ...

  4. 分类-MNIST(手写数字识别)

    这是学习<Hands-On Machine Learning with Scikit-Learn and TensorFlow>的笔记,如果此笔记对该书有侵权内容,请联系我,将其删除. 这 ...

  5. Hadoop日记Day5---HDFS介绍

    一.HDFS介绍 1.1 背景 随着数据量越来越大,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式 ...

  6. Elasticsearch Java Rest Client API 整理总结 (一)——Document API

    目录 引言 概述 High REST Client 起步 兼容性 Java Doc 地址 Maven 配置 依赖 初始化 文档 API Index API GET API Exists API Del ...

  7. 后端自动构建前端css和js

    引子: 别的复杂前端开发技术不会,用得多的还是手写代码,手动处理. 3年前手写合并压缩js和css文件的asp脚本代码目前还能正常运行,也就没有多大使用别的技术的动力. 直到近期被一个问题纠结着,今天 ...

  8. wkhtmltopdf 参数介绍

    wkhtmltopdf [OPTIONS]... <input file> [More input files] <output file> 常规选项   --allow &l ...

  9. A - 摆仙果

    题目描述 Adrian, Bruno与Goran三人参加了仙界的宴会,宴会开始之前先准备了一些仙果供三人品尝,但是仙果的摆放有顺序要求,如果把仙果摆错了位置,仙果就会消失而无法品尝到. 由于三人是第一 ...

  10. Individual Project Records

    At the midnight of September 20, I finished my individual projcet -- a word frequency program. You c ...