题目传送门


分析

可以发现相同的颜色一定组成一个连通块。

那么操作2就相当于 \(f_x+f_y-2*f_{lca}+1\)

操作3就相当于询问 \(f\) 的最大值。

最关键的就是操作1,考虑往上跳,在同颜色与同重链之间选深度较大的一个。

那么就是要把重链上的这一段染成新的颜色,在线段树上维护颜色以及f值。

现在的链顶的子树所有的 \(f\) 都要减1,并且如果之前子树的点操作过那么就要撤销回来。

然后如果当前点不是原颜色的链底,那么当前点的那一子节点的子树就要整体加一。

颜色的链顶和链底可以在修改的时候动态维护,这样时间复杂度就是两个 \(\log\) 的


代码

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
using namespace std;
const int N=100011; struct node{int y,next;}e[N<<1]; vector<int>K[N];
int as[N],dep[N],siz[N],tot,ext,n,m,et=1,fat[N],big[N],Top[N],dfn[N],rfn[N],nfd[N];
int lazy[N<<2],w[N<<2],col[N<<2],ct[N<<1],cb[N<<1];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void dfs1(int x,int fa){
dep[x]=dep[fa]+1,siz[x]=1,fat[x]=fa;
for (int i=as[x],SIZ=-1;i;i=e[i].next)
if (e[i].y!=fa){
dfs1(e[i].y,x),siz[x]+=siz[e[i].y];
if (SIZ<siz[e[i].y]) big[x]=e[i].y,SIZ=siz[e[i].y];
}
}
void dfs2(int x,int linp){
dfn[x]=++tot,nfd[tot]=x,Top[x]=linp;
if (!big[x]) return;
dfs2(big[x],linp),K[x].push_back(dfn[big[x]]);
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fat[x]&&e[i].y!=big[x])
dfs2(e[i].y,e[i].y),K[x].push_back(dfn[e[i].y]);
}
int max(int a,int b){return a>b?a:b;}
void build(int k,int l,int r){
if (l==r){
w[k]=dep[nfd[l]],col[k]=nfd[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
w[k]=max(w[k<<1],w[k<<1|1]);
}
int lca(int x,int y){
for (;Top[x]!=Top[y];x=fat[Top[x]])
if (dep[Top[x]]<dep[Top[y]]) x^=y,y^=x,x^=y;
return dep[x]<dep[y]?x:y;
}
void ptag(int k,int z){w[k]+=z,lazy[k]+=z;}
void update(int k,int l,int r,int x,int y,int z){
if (l==x&&r==y) {ptag(k,z); return;}
int mid=(l+r)>>1;
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
if (y<=mid) update(k<<1,l,mid,x,y,z);
else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
w[k]=max(w[k<<1],w[k<<1|1]);
}
void upd(int k,int l,int r,int x,int y,int z){
if (l==x&&r==y) {col[k]=z; return;}
int mid=(l+r)>>1;
if (y<=mid) upd(k<<1,l,mid,x,y,z);
else if (x>mid) upd(k<<1|1,mid+1,r,x,y,z);
else upd(k<<1,l,mid,x,mid,z),upd(k<<1|1,mid+1,r,mid+1,y,z);
}
int query_col(int k,int l,int r,int x){
if (l==r) return col[k];
int mid=(l+r)>>1;
if (x<=mid) return max(col[k],query_col(k<<1,l,mid,x));
else return max(col[k],query_col(k<<1|1,mid+1,r,x));
}
int query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return w[k];
int mid=(l+r)>>1;
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return max(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
void Update(int x){
ct[++ext]=1,cb[ext]=x;
for (int lst=0,Ct=0;x;x=fat[lst]){
int col=query_col(1,1,n,dfn[x]);
int w=query(1,1,n,dfn[x],dfn[x]);
if (x!=cb[col]){
int now=nfd[*(--upper_bound(K[x].begin(),K[x].end(),dfn[cb[col]]))];
if (now!=lst) update(1,1,n,dfn[now],rfn[now],1),Ct=now;
}
if (dep[ct[col]]<dep[Top[x]]){
update(1,1,n,dfn[Top[x]],rfn[Top[x]],1-w);
upd(1,1,n,dfn[Top[x]],dfn[x],ext);
if (lst) update(1,1,n,dfn[lst],rfn[lst],w-1);
lst=Top[x];
}else{
update(1,1,n,dfn[ct[col]],rfn[ct[col]],1-w);
upd(1,1,n,dfn[ct[col]],dfn[x],ext);
if (lst) update(1,1,n,dfn[lst],rfn[lst],w-1);
lst=ct[col],ct[col]=Ct;
}
}
}
int main(){
ext=n=iut(),m=iut();
for (int i=1;i<n;++i){
int x=iut(),y=iut();
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
for (int i=1;i<=n;++i) ct[i]=cb[i]=i;
dfs1(1,0),dfs2(1,1),build(1,1,n);
for (int i=1;i<=n;++i) rfn[i]=dfn[i]+siz[i]-1;
for (int i=1;i<=m;++i){
int opt=iut(),x=iut();
switch (opt){
case 1:{
Update(x);
break;
}
case 2:{
int y=iut(),Lca=lca(x,y),t0,t1,t2;
t0=query(1,1,n,dfn[x],dfn[x]);
t1=query(1,1,n,dfn[y],dfn[y]);
t2=query(1,1,n,dfn[Lca],dfn[Lca]);
print(t0+t1-t2*2+1),putchar(10);
break;
}
case 3:{
print(query(1,1,n,dfn[x],rfn[x])),putchar(10);
break;
}
}
}
return 0;
}

#轻重链剖分,线段树#洛谷 3703 [SDOI2017]树点涂色的更多相关文章

  1. 洛谷3703 SDOI2017树点涂色(LCT+线段树+dfs序)

    又一道好题啊qwqqqq 一开始看这个题,还以为是一个树剖的什么毒瘤题目 (不过的确貌似可以用树剖啊) qwq这真是一道\(LCT\)维护颜色的好题 首先,我们来一个一个操作的考虑. 对于操作\(1\ ...

  2. 洛谷3703 [SDOI2017] 树点染色 【LCT】【线段树】

    题目分析: 操作一很明显等价于LCT上的access操作,操作二是常识,操作三转化到dfs序上求最大值也是常识.access的时候顺便在线段树中把对应部分-1,把右子树的子树+1即可. 代码: #in ...

  3. 洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)

    洛谷题目传送门 闲话 这是所有LCT题目中的一个异类. 之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合. 只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要 ...

  4. 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)

      2020/4/30   15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...

  5. 洛谷1087 FBI树 解题报告

    洛谷1087 FBI树 本题地址:http://www.luogu.org/problem/show?pid=1087 题目描述 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全 ...

  6. 洛谷P3018 [USACO11MAR]树装饰Tree Decoration

    洛谷P3018 [USACO11MAR]树装饰Tree Decoration树形DP 因为要求最小,我们就贪心地用每个子树中的最小cost来支付就行了 #include <bits/stdc++ ...

  7. 洛谷P3979 遥远的国度 树链剖分+分类讨论

    题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...

  8. 洛谷 P3781 - [SDOI2017]切树游戏(动态 DP+FWT)

    洛谷题面传送门 SDOI 2017 R2 D1 T3,nb tea %%% 讲个笑话,最近我在学动态 dp,wjz 在学 FWT,而我们刚好在同一天做到了这道题,而这道题刚好又是 FWT+动态 dp ...

  9. 洛谷 P3714 - [BJOI2017]树的难题(点分治)

    洛谷题面传送门 咦?鸽子 tzc 竟然来补题解了?incredible( 首先看到这样类似于路径统计的问题我们可以非常自然地想到点分治.每次我们找出每个连通块的重心 \(x\) 然后以 \(x\) 为 ...

  10. 洛谷P3830 随机树(SHOI2012)概率期望DP

    题意:中文题,按照题目要求的二叉树生成方式,问(1)叶平均深度 (2)树平均深度 解法:这道题看完题之后完全没头绪,无奈看题解果然不是我能想到的qwq.题解参考https://blog.csdn.ne ...

随机推荐

  1. C++ 多线程的错误和如何避免(2)

    试图 join 一个已经 detach 的线程 如果你已经在某个地方分离了线程,那你不可以在主线程再次 join,这是一个明显的错误 比如: #include <iostream> #in ...

  2. Golang Web 框架 Gin 基础学习教程集合目录

    Gin Web 框架基础学习系列目录 01-quickstart 02-parameter 03-route 04-middleware 05-log 06-logrus 07-bind 08-val ...

  3. 【Android 逆向】【攻防世界】easy-so

    1. apk安装到手机,随便输入点内容,提示错误 2. jadx打开apk btn.setOnClickListener(new View.OnClickListener() { // from cl ...

  4. SpringBoot的自动装配原理及应用

    什么是SpringBoot自动装配 所谓的"SpringBoot自动装配"就是指:通过注解和一些简单的配置就能将某些组件载入Spring容器环境中,便于使用. 比如,很多sprin ...

  5. 单继承,多继承,菱形继承---day21

    1.单继承 # ### 继承:一个类除了自身所有用的属性方法之外,还获取了另外一个类的成员属性和方法 ''' 一个类继承另外一个类,那么该类就是子类(衍生类),被继承的这个类就叫做父类(基类,超类) ...

  6. java基础集合类之ArrayList---01

    集合类之ArrayList ArrayList<E>: 1.可调整大小的数组实现 2.<E>:是一种特殊的数据类型,泛型 3.在出现E的地方我们使用引用数据类型替换即可:Arr ...

  7. Mac环境下, VMware Fusion Pro下的虚拟机( CentOS 7)的 NAT网络配置

    前提实现说明 1.vm版本VMware Fusion Pro 12.1.0 2.centos版本centos7.6 1.虚拟机能访问外网,虚拟机能访问mac本机: 2.mac本机可以连接虚拟机 操作步 ...

  8. 问题:django中对datetime类型数据在pycharm中sqlite3进行修改时,修改后datetime日期数据变成了时间戳类型

    这是正在修改的 提交完之后 问题原因 问题原因是sqlite数据库对日期类型不敏感,Pycharm直接插入会变成图中这样的时间戳,用POST请求添加数据或Django自带的后台管理插入不会有这样的问题 ...

  9. logstash部署及项目日志输出到ES

    目录 logstash简介 安装logstash logstash的基本语法 测试标准输入输出 测试输出到文件 测试输出到ES 指定配置文件启动 配置文件内容 后台运行脚本 参考 logstash简介 ...

  10. 【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.

    问题描述 PHP的Web Job,通过artisan来配置路径启动PHP任务,相关启动脚本如下: artisan_path = "d:\\home\\site\\wwwroot"; ...