以最后被删去的点为根,这样子不会存在从父亲然后删掉某个点,儿子的删除顺序一定比父亲前。

记每个点子树中的最大值为 \(f_x\),那么一个点的排名,首先就需要加上 \(<f_x\) 的所有值,记对应 \(f_x\) 的点为 \(y\),那么 \(y\) 一定会一路上来删掉 \(x\)。

所以一个点排名就是 \(<f_x\) 的所有值,再加上 \(x,y\) 之间的距离。

考虑如何维护修改,设上一个根是 \(rt\),新根是 \(x\),那么等价于一次换根,需要将 \(x\) 到 \(rt\) 这条路径 cover 上 \(p_{rt}\),同时改掉 \(x\) 的值。

可以使用 ODT + 树剖维护。

Code
const int N=2e5+5;
int n,m;
vi G[N];
int dep[N],siz[N],top[N],son[N],dfn[N],fat[N],dfc,p[N*2],rp[N*2];
void dfs1(int u,int fa) {
dep[u]=dep[fa]+1,siz[u]=1,fat[u]=fa;
for(int v:G[u]) if(v!=fa) {
dfs1(v,u),siz[u]+=siz[v];
p[u]=max(p[u],p[v]);
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int tp,int fa) {
top[u]=tp,dfn[u]=++dfc;
if(son[u]==0) return;
dfs2(son[u],tp,u);
for(int v:G[u]) if(v!=fa&&v!=son[u]) dfs2(v,v,u);
}
int bit[2*N];
void add(int x,int v) { for(;x<=n+m;x+=(x&-x)) bit[x]+=v; }
int ask(int x) { int ret=0; for(;x;x-=(x&-x)) ret+=bit[x]; return ret; }
struct node {
int l,r,v;
node() {}
node(int L,int R,int V) { l=L,r=R,v=V; }
bool operator < (const node &a) const { return l<a.l; }
};
set<node> odt;
auto spilt(int p) {
auto it=odt.lower_bound(node(p,-1,0));
if(it!=odt.end()&&it->l==p) return it;
--it;
int l=it->l,r=it->r,v=it->v;
odt.erase(it),odt.insert(node(l,p-1,v));
return odt.insert(node(p,r,v)).fi;
}
void cover(int l,int r,int v) {
auto itr=spilt(r+1),itl=spilt(l);
for(auto it=itl;it!=itr;it=odt.erase(it)) add(it->v,-((it->r)-(it->l)+1));
add(v,r-l+1),odt.insert(node(l,r,v));
}
void update(int u,int v,int w) {
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
cover(dfn[top[u]],dfn[u],w),u=fat[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
cover(dfn[u],dfn[v],w);
}
int lca(int u,int v) {
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fat[top[u]];
}
return dep[u]<dep[v]?u:v;
}
int dist(int u,int v) { return dep[u]+dep[v]-2*dep[lca(u,v)]+1; }
int query(int x) {
auto pos=odt.upper_bound(node(dfn[x],-1,0));
int val=prev(pos)->v;
return ask(val-1)+dist(x,rp[val]);
}
int main() {
n=read(),m=read();
FOR(i,1,n-1) {
int x=read(),y=read();
G[x].pb(y),G[y].pb(x);
}
FOR(i,1,n) p[i]=rp[i]=i;
int rt=n,mx=n;
dfs1(n,0),dfs2(n,n,0);
FOR(i,1,n) add(p[i],1),odt.insert(node(dfn[i],dfn[i],p[i]));
FOR(i,1,m) {
string ch; cin>>ch;
int u=read();
if(ch[0]=='1') {
if(u!=rt) update(rt,u,mx);
++mx,cover(dfn[u],dfn[u],mx),rp[mx]=rt=u;
}
else if(ch[0]=='2') printf("%d\n",query(u));
else { int v=read(); printf("%d\n",query(u)>query(v)?v:u);}
}
}

CF1137F Matches Are Not a Child's Play 题解的更多相关文章

  1. CF1137F Matches Are Not a Child's Play(LCT思维题)

    题目 CF1137F 很有意思的题目 做法 直接考虑带修改的做法,上一次最大值为u,这次修改v,则最大值为v了 我们发现:\(u-v\)这条链会留到最后,序列里的其他元素相对位置不变,这条链会\(u\ ...

  2. CF1137F Matches Are Not a Child's Play(树链剖分)

    题面 我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当前序列的最末端,最后只剩下一个节点时将该节点的编号加入到结尾. 例如对于上图中的树,它的删除序列为:2 4 3 1 ...

  3. 【树链剖分 ODT】cf1137F. Matches Are Not a Child's Play

    孔爷的杂题系列:LCT清新题/ODT模板题 题目大意 定义一颗无根树的燃烧序列为:每次选取编号最小的叶子节点形成的序列. 要求支持操作:查询一个点$u$在燃烧序列中的排名:将一个点的编号变成最大 $n ...

  4. CF1137F Matches Are Not a Child's Play

    我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当前序列的最末端,最后只剩下一个节点时将该节点的编号加入到结尾.现在给出一棵n个节点的树,有m次操作: up v:将v号节 ...

  5. [cf1137F]Matches Are Not a Child's Pla

    显然compare操作可以通过两次when操作实现,以下仅考虑前两种操作 为了方便,将优先级最高的节点作为根,显然根最后才会被删除 接下来,不断找到剩下的节点中(包括根)优先级最高的节点,将其到其所在 ...

  6. [Codeforces1137F]Matches Are Not a Child's Play——LCT+树状数组

    题目链接: [Codeforces1137F]Matches Are Not a Child's Play 题目大意: 我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当 ...

  7. Codeforces 1137F Matches Are Not a Child's Play [LCT]

    Codeforces 很好,通过这题对LCT的理解又深了一层. 思路 (有人说这是套路题,然而我没有见过/kk) 首先发现,删点可以从根那里往下删,非常难受,所以把权值最大的点提为根. 然后考虑\(x ...

  8. Codeforces 1137F - Matches Are Not a Child's Play(LCT)

    Codeforces 题面传送门 & 洛谷题面传送门 考虑将一个点 \(x\) 的编号变为当前所有点编号最大值 \(+1\) 会对每个点的删除时间产生怎么样的影响.由于编号最大的点肯定是最后一 ...

  9. The Child and Zoo 题解

    题目描述 Of course our child likes walking in a zoo. The zoo has n areas, that are numbered from 1 to n. ...

  10. LCT[Link-Cut-Tree学习笔记]

    部分摘抄于 FlashHu candy99 所以文章篇幅较长 请有足够的耐心(不是 其实不用学好splay再学LCT的-/kk (至少现在我平衡树靠fhq) 如果学splay的话- 也许我菜吧-LCT ...

随机推荐

  1. Python使用pipreqs生成requirements.txt

    当一个Python完成后,若要在新环境下运行,往往需要重新安装各种包依赖,这就需要记录当前环境下所用到的包.包的版本等,非常麻烦,这里介绍一种方法,可以较为快速便捷地生成requirements.tx ...

  2. 用Echarts实现SpreadJS引用从属关系可视化

    在金融行业,我们经常会有审计审查的需求,对某个计算结果进行审查,但是这个计算结果可能依赖多个单元格,而且会有会有多级依赖的情况,如果让我们的从业人员靠眼睛找,工作量巨大,而且准确性存疑,基本上死路一条 ...

  3. misc之套娃编码解密

    题目: 01100101 01100110 00100000 01100010 01100101 00100000 00111001 01100110 00100000 01100011 011001 ...

  4. DevSecOps 需要知道的十大 K8s 安全风险及建议

    Kubernetes (K8s)是现代云原生世界中的容器管理平台.它实现了灵活.可扩展地开发.部署和管理微服务.K8s 能够与各种云提供商.容器运行时接口.身份验证提供商和可扩展集成点一起工作.然而 ...

  5. 三台服务器使用docker搭建redis一主二从三哨兵,概念-搭建-整合springboot

    一.前言 redis在我们企业级开发中是很常见的,但是单个redis不能保证我们的稳定使用,所以我们要建立一个集群. redis有两种高可用的方案: High availability with Re ...

  6. css、js 缓存清除

    此种方式完美达到了清除缓存的效果 css引入标签可在一个引号内完成,js引入标签由于解析原因需要将两个标签拆开再组 使用:按照此格式,放在原 <link /> 或 <script&g ...

  7. ArcGIS工具 - 批量合并数据库

    在ArcGIS数据建库和入库过程中,经常需要将数据结构相同.数据内容不同的多个数据库文件进行合并,使用工具臬中复制.合并.追加都可以达到一定的效果,但都不能直接支持数据库的操作.当合并成百上千个数据库 ...

  8. 2023牛客寒假算法基础集训营2 ABCDEFHJKL

    比赛链接 A 题解 知识点:数学. 用 \(n\) 减去区间1的端点得到匹配的一个区间,求一下与区间2的交集. 一个小公式,两区间 \([L_1,R_1]\) 和 \([L_2,R_2]\) 的交集长 ...

  9. post方法易错地方

    <body> <h1>登录</h1> <input type="text" placeholder="请输入用户名" ...

  10. Unity_UIWidgets - 组件AppBar

    Unity_UIWidgets - 组件AppBar AppBar 构造 构造png观看 使用代码 使用效果 AppBar使用结束 结语 图标Icon QQ 今日无推荐 Unity_UIWidgets ...