题目传送门


分析

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

那么操作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. 【Android逆向】frida 破解 jwxdxnx02.apk

    apk 路径: https://pan.baidu.com/s/1cUInoi 密码:07p9 这题比较简单,主要是用于练习frida 1. 安装apk到手机 需要输入账号密码 2. 使用jdax 查 ...

  2. 国内无法下载k8s镜像的解决办法

    关于通过各种方法下载k8s相关镜像的方法总结如下: 1.使用Azure中国镜像站,目前限制只能"Azure China IP"可用,不再对外提供服务,此路不通. 2.直接使用mir ...

  3. 字符串,format格式化及列表的相关进阶操作---day07

    1.字符串相关操作 (1)字符串的拼接 (2)字符串的重复 (3)字符串跨行拼接 (4)字符串的索引 (5)字符串的切片:[开始索引:结束索引:步长] 2.字符串的格式化format (1)顺序传参 ...

  4. time模块,os操作系统及os模块和shutil模块用法---day16

    1.时间模块 import time time.time() 获取本地时间戳 localtime() 获取本地时间元组,参数是时间戳,默认不写是当前 ***** mktime() 通过时间元组获取时间 ...

  5. ZYNQ核心板及其底板开源啦!

    Hello-FPGA ZYNQ 设计开源啦! 开源ZYNQ核心板 + 底板 硬件设计.软件设计,软件设计使用裸机演示,演示了如何使用AXI DMA等关键dma 模块 欢迎加QQ 讨论 94755958 ...

  6. 【Azure 事件中心】Spring Cloud Stream Event Hubs Binder 发送Event Hub消息遇见 Spec. Rule 1.3 - onSubscribe, onNext, onError and onComplete signaled to a Subscriber MUST be signaled serially 异常

    问题描述 开发Java Spring Cloud应用,需要发送消息到Azure Event Hub中.使用 Spring Cloud Stream Event Hubs Binder 依赖,应用执行一 ...

  7. 【Azure Redis 缓存】使用Azure Redis服务时候,如突然遇见异常,遇见命令Timeout performing SET xxxxxx等情况,如何第一时间查看是否有Failover存在呢?

    问题描述 使用Azure Redis服务时,如突然遇见异常,命令Timeout performing SET xxxxxx等情况,如何第一时间查看是否有Failover存在呢?看是否有进行平台的维护呢 ...

  8. 摆脱鼠标系列 - 打开微信(Alt+V) - 打开双核浏览器(Alt+S) - HotkeyP

    摆脱鼠标系列 - 打开微信(Alt+V) - 打开双核浏览器(Alt+S) - HotkeyP 新定义了两个快捷键 这两个比较常用

  9. ubuntu16.04 关闭系统的屏幕阅读功能

    在安装audacity的时候,不知道点到哪里,电脑突然就不停的"Chinese Letter",后面仔细听,鼠标点到那里就会读那里文字,键盘输入也是,联想到Android上也有类似 ...

  10. 风控规则引擎(一):Java 动态脚本

    风控规则引擎(一):Java 动态脚本 日常场景 共享单车会根据微信分或者芝麻分来判断是否交押金 汽车租赁公司也会根据微信分或者芝麻分来判断是否交押金 在一些外卖 APP 都会提供根据你的信用等级来发 ...