[Codeforces1137F]Matches Are Not a Child's Play——LCT+树状数组
题目链接:
[Codeforces1137F]Matches Are Not a Child's Play
题目大意:
我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当前序列的最末端,最后只剩下一个节点时将该节点的编号加入到结尾。

例如对于上图中的树,它的删除序列为:$2\ 4\ 3\ 1\ 5$
现在给出一棵$n$个节点的树,有$m$次操作:
$up\ v$:将$v$号节点的编号变为当前所有节点编号的$max+1$
$when\ v$:查询$v$在当前树的删除序列中是第几号元素
$compare\ u\ v$:查询$u$和$v$在当前树的删除序列中谁更靠前
显然编号最大的点在序列的最后一位(设为$y$),我们以这个点为根,那么删除就是从下往上删除一段一段的链。
将连续删除的一段链看成是一条重链,整棵树就被分成了若干条重链。
可以发现每条重链的最低端的节点标号是这条重链上最大的。
因为如果要删除链底的那个点,那么说明当前能删除的点都比链底的点大,在删除链底之后一定会连续删除链上的所有点。
现在来考虑一次$up\ x$操作带来的影响:显然最后删除的一定是从$y$到$x$的链,而剩下的点在序列上的相对位置不变。
对于树来说就是将$x$到$y$变成一条重链并将$x$变为根节点。
我们用$LCT$来维护这些重链,对于每条重链按链上的编号最大值来编号,用树状数组来记录每个重链的大小。
$up$操作就相当于$LCT$中的$access$,在$access$时同步修改树状数组上记录的信息即可。
$when$操作就是查重链编号比自己所在重链的编号小的所有重链大小之和及自己所在重链下方的节点数。
$compare$操作就是两个$when$操作。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int f[200010];
int s[200010][2];
int size[200010];
int st[200010];
int v[400010];
int tot;
int head[200010];
int nex[400010];
int to[400010];
char ch[10];
int n,m;
int x,y;
int cnt;
int rev[200010];
int val[200010];
void add_edge(int x,int y)
{
nex[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void add(int x,int k)
{
for(int i=x;i<=n+m;i+=i&-i)
{
v[i]+=k;
}
}
int ask(int x)
{
int res=0;
for(int i=x;i;i-=i&-i)
{
res+=v[i];
}
return res;
}
void dfs(int x)
{
val[x]=x;
size[x]=1;
for(int i=head[x];i;i=nex[i])
{
if(to[i]!=f[x])
{
f[to[i]]=x;
dfs(to[i]);
if(val[to[i]]>val[x])
{
val[x]=val[to[i]];
s[x][1]=to[i];
size[x]=size[to[i]]+1;
}
}
}
add(val[x],1);
}
bool is_root(int rt)
{
return rt!=s[f[rt]][0]&&rt!=s[f[rt]][1];
}
bool get(int rt)
{
return rt==s[f[rt]][1];
}
void pushup(int rt)
{
size[rt]=size[s[rt][0]]+size[s[rt][1]]+1;
}
void pushdown(int rt)
{
if(rev[rt])
{
swap(s[rt][0],s[rt][1]);
rev[s[rt][0]]^=1;
rev[s[rt][1]]^=1;
rev[rt]=0;
}
if(s[rt][0])val[s[rt][0]]=val[rt];
if(s[rt][1])val[s[rt][1]]=val[rt];
}
void rotate(int rt)
{
int fa=f[rt];
int anc=f[fa];
int k=get(rt);
if(!is_root(fa))
{
s[anc][get(fa)]=rt;
}
s[fa][k]=s[rt][k^1];
f[s[rt][k^1]]=fa;
s[rt][k^1]=fa;
f[fa]=rt;
f[rt]=anc;
pushup(fa);
pushup(rt);
}
void splay(int rt)
{
int top=0;
st[++top]=rt;
for(int i=rt;!is_root(i);i=f[i])
{
st[++top]=f[i];
}
for(int i=top;i>=1;i--)
{
pushdown(st[i]);
}
for(int fa;!is_root(rt);rotate(rt))
{
if(!is_root(fa=f[rt]))
{
rotate(get(fa)==get(rt)?fa:rt);
}
}
}
void access(int rt)
{
for(int x=0;rt;x=rt,rt=f[rt])
{
splay(rt);
s[rt][1]=0;
pushup(rt);
add(val[rt],-size[rt]);
add(cnt,size[rt]);
s[rt][1]=x;
pushup(rt);
}
}
void reverse(int rt)
{
cnt++;
access(rt);
splay(rt);
rev[rt]^=1;
val[rt]=cnt;
}
int query(int rt)
{
splay(rt);
return ask(val[rt])-size[s[rt][0]];
}
int main()
{
scanf("%d%d",&n,&m);
cnt=n;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
dfs(n);
for(int i=1;i<=m;i++)
{
scanf("%s",ch);
if(ch[0]=='u')
{
scanf("%d",&x);
reverse(x);
}
else if(ch[0]=='w')
{
scanf("%d",&x);
printf("%d\n",query(x));
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",query(x)<query(y)?x:y);
}
}
}
[Codeforces1137F]Matches Are Not a Child's Play——LCT+树状数组的更多相关文章
- CF1137F Matches Are Not a Child's Play(LCT思维题)
题目 CF1137F 很有意思的题目 做法 直接考虑带修改的做法,上一次最大值为u,这次修改v,则最大值为v了 我们发现:\(u-v\)这条链会留到最后,序列里的其他元素相对位置不变,这条链会\(u\ ...
- CF1137F Matches Are Not a Child's Play(树链剖分)
题面 我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当前序列的最末端,最后只剩下一个节点时将该节点的编号加入到结尾. 例如对于上图中的树,它的删除序列为:2 4 3 1 ...
- Codeforces 1137F Matches Are Not a Child's Play [LCT]
Codeforces 很好,通过这题对LCT的理解又深了一层. 思路 (有人说这是套路题,然而我没有见过/kk) 首先发现,删点可以从根那里往下删,非常难受,所以把权值最大的点提为根. 然后考虑\(x ...
- 【树链剖分 ODT】cf1137F. Matches Are Not a Child's Play
孔爷的杂题系列:LCT清新题/ODT模板题 题目大意 定义一颗无根树的燃烧序列为:每次选取编号最小的叶子节点形成的序列. 要求支持操作:查询一个点$u$在燃烧序列中的排名:将一个点的编号变成最大 $n ...
- CF1137F Matches Are Not a Child's Play
我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当前序列的最末端,最后只剩下一个节点时将该节点的编号加入到结尾.现在给出一棵n个节点的树,有m次操作: up v:将v号节 ...
- [cf1137F]Matches Are Not a Child's Pla
显然compare操作可以通过两次when操作实现,以下仅考虑前两种操作 为了方便,将优先级最高的节点作为根,显然根最后才会被删除 接下来,不断找到剩下的节点中(包括根)优先级最高的节点,将其到其所在 ...
- Codeforces 1137F - Matches Are Not a Child's Play(LCT)
Codeforces 题面传送门 & 洛谷题面传送门 考虑将一个点 \(x\) 的编号变为当前所有点编号最大值 \(+1\) 会对每个点的删除时间产生怎么样的影响.由于编号最大的点肯定是最后一 ...
- Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间取摸
D. The Child and Sequence Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest ...
- Codeforces 438D The Child and Sequence - 线段树
At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at ...
随机推荐
- robot framework 关键字Switch Browser和Select Window的区别
Switch Browser针对的是2个Open Browser以上的切换:Select Window针对的是1个Open Browser里面某个点击事件打开了另外一个新窗口 1.例子 Switch ...
- Hadoop HA 搭建
Hadoop HA 什么是 HA HA是High Available缩写,是双机集群系统简称,指高可用性集群,是保证业务连续性的有效解决方案,一般有两个或两个以上的节点,且分为活动节点及备用节点.通常 ...
- Canvas 绘制一个像素风电子时钟
想法是在 Canvas 上绘制由小方块组成的数字. 第一步是实现绘制小方块的方法,先画出一个边长为 5 的 10x10 个方块,使用两个 for 循环很简单就能完成. for (let i = 0; ...
- FICO-Payment Terms 收付款条件和分期付款设置
转载:https://www.cnblogs.com/weichuo/p/3524278.html Payment Terms 收付款条件和分期付款设置 SAP Payment Terms 中文翻译为 ...
- 2019年6月车型数据Access数据库+缩略图 更新于2019年6月5日.
工作需要才来采集的, 数据来源某卡汽车网, 分享出来给需要的人吧, 本着分享的精神, 我就不猥琐的放到csdn下载了 本来是sql server的, 我导出到access了, 也方便大家查看. 顺手抓 ...
- ChibiOS/RT移植到STM32F407
官网地址:http://www.chibios.org/dokuwiki/doku.php 下载源码 找到STM32F407的demos程序(chibios\demos\STM32\RT-STM32F ...
- IDEA配置maven报错解决方案
主要是得分清楚你的本地maven库,以及maven安装根目录 ,一般你自己安装maven成功后,电脑默认读取的库位置在C盘下面. 只要把路径指向搞对了,就没什么问题了 .
- ubuntu18.04 安装android studio
首先从官网下载android studio:Android Studio (安装前应先安装JDK环境) 得到android-studio-ide-191.5977832-linux.tar.gz 在安 ...
- Oracle表空间满处理方式
一.查询表空间常规语句 1.查询表空间使用情况 SELECT Upper(F.TABLESPACE_NAME) "表空间名", D.TOT_GROOTTE_MB ...
- java - day012 - 异常 , throws, throw , IO ,RandomAccessFile
异常 封装错误信息的对象 错误信息 类型 例如: NullPointerExce 空指针 提示消息 出错的行号 异常的继承结构 Throwable | - Error 系统级错误 | ...