[CF1534H]Lost Nodes
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1534H]Lost Nodes相关的知识,希望对你有一定的参考价值。
Lost Nodes
题解
我觉得正常的出题人大概都不会这样出题。
首先我们考虑对于一棵树,我们怎么求出它的最小询问次数。
我们不妨先假设我们知道已经给出的
c
c
c,我们的目标是找到
c
c
c为最坏情况时我们的最少询问次数。
我们先以假想的
c
c
c为树的根。
考虑树
d
p
dp
dp,定义
f
i
f_{i}
fi表示对于点
i
i
i,知道它的子树内的一个端点的最小代价。
很明显,当我们询问
x
x
x时,如果
x
x
x在
a
a
a到
b
b
b的路径上,他会返回
x
x
x,否则会返回
x
x
x子树内的一点。
我们已经知道了我们的根在路径上,那么对于一个叶子节点,只需要一次询问,所以有
f
l
e
a
f
=
1
f_{leaf}=1
fleaf=1。
那么对于非叶子节点,显然如果它不在路径上,我们询问它子树中的点一次即可得知,当它在路径上时,就需要一个一个儿子的枚举。
我们假设节点
u
u
u有
k
k
k个儿子,第
i
i
i个枚举到的儿子是
p
i
p_{i}
pi,很明显,有
f
u
=
max
i
=
1
k
f
p
i
+
i
−
1
f_{u}=\\max_{i=1}^{k}f_{p_{i}}+i-1
fu=i=1maxkfpi+i−1
我们考虑怎么让这个最大值最小。
很明显,由于
i
i
i是递增的,所以当
f
f
f不递增时我的
f
u
f_{u}
fu肯定是最小的,所以我们枚举的
p
p
p应该按
f
f
f的大小排序。
但我们的端点有两个,考虑如何求出这两个点。
对于有点端点是根的情况,这明显是不会不会比有两个点都不是根的情况大的,我们可以不用考虑。
假设对于根的儿子排序是
p
p
p,由于我们只会在两个端点都求出来时才退出,有
a
n
s
=
max
1
⩽
i
<
j
⩽
k
f
p
i
+
f
p
j
+
j
−
1
ans=\\max_{1\\leqslant i<j\\leqslant k}f_{p_{i}}+f_{p_{j}}+j-1
ans=1⩽i<j⩽kmaxfpi+fpj+j−1
同样,这个的答案也是在
p
p
p是不升的排序时最大。
如果要最大,我们肯定会让最大的一个在最前面,最大一个在其他任何地方都是不优的,而后面的就跟前面的
d
p
dp
dp一样了。
所以我们的儿子一直都是按照它们的
f
f
f值大小排序,求出根的
a
n
s
ans
ans即可。
容易看出,第一个儿子是必选的,所以有
a
n
s
=
f
p
1
+
max
i
=
2
k
f
p
i
+
i
−
1
ans=f_{p_{1}}+\\max_{i=2}^{k}f_{p_{i}}+i-1
ans=fp1+i=2maxkfpi+i−1
但事实上我们是不知道根的,所以我们不得不加上一个换根。
但如果涉及换根的话,相当于我们就要动态维护子节点的
f
f
f值大小顺序,我们可以考虑用FHQ_Treap对其进行维护。
我们每次插入
f
i
f_{i}
fi时就将它插入到
f
i
f_{i}
fi所对应的位置,由于我们
f
f
f与
a
n
s
ans
ans的转移涉及到排名,我们可以用懒标记对其进行维护。也就是裂成两半后对该点加上它前面的点的个数,对于后半部分整体加一。
我们的答案相当于对换到的每个根的最大值取最大值即可。
有了换根
d
p
dp
dp的过程,我们自然也就知道如何求出端点了。
当我们枚举一个子树时,对其一个叶子节点进行询问。
如果询问的答案不在这个子树内,我们可以直接退出去询问下一个儿子。
如果在这个子树内时,我们就可以确定该端点一定在这个子树内,一直返回到那个节点,在对于那个节点的其它儿子进行上述操作。
当我们返回的点为叶子或其儿子节点都不在树上时,就可以确定其为端点了。
其实跟我们
d
p
dp
dp的思想差不多,不过由于
f
f
f值已经确定了,不用
T
r
e
a
p
Treap
Treap维护,直接排序即可。
容易发现,该做法的时间复杂度为 O ( n l o g n ) O\\left(nlog\\,n\\right) O(nlogn)。
源码
千万别像笔者一样最后忘记排序了。但代码还是rank1
50发提交创下记录。
后略。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int iv2=5e8+4;
const int lim=1000000;
const int jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,head[MAXN],tot,dp[MAXN],ans,dd[2];
vector<int>G[MAXN];
struct edge{int to,nxt;}e[MAXN<<1];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
class TreapTree{
private:
int cnt,siz[MAXN*3],ch[MAXN*3][2],rnd[MAXN*3],pri[MAXN*3];
int val[MAXN*3],maxx[MAXN*3],lzy[MAXN*3],root[MAXN*3];
int newnode(int v,int w){
int x=++cnt;siz[x]=1;rnd[x]=rand();ch[x][0]=ch[x][1]=0;
pri[x]=v;maxx[x]=val[x]=w;lzy[x]=0;return x;
}
void pushup(int x){
siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];maxx[x]=val[x];
if(ch[x][0])maxx[x]=max(maxx[ch[x][0]],maxx[x]);
if(ch[x][1])maxx[x]=max(maxx[ch[x][1]],maxx[x]);
}
void Add(int x,int y){if(!x)return ;lzy[x]+=y;maxx[x]+=y;val[x]+=y;}
void pushdown(int x){if(!lzy[x])return ;Add(ch[x][0],lzy[x]);Add(ch[x][1],lzy[x]);lzy[x]=0;}
int merge(int a,int b)以上是关于[CF1534H]Lost Nodes的主要内容,如果未能解决你的问题,请参考以下文章