[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+i1
我们考虑怎么让这个最大值最小。
很明显,由于 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=1i<jkmaxfpi+fpj+j1
同样,这个的答案也是在 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+i1

但事实上我们是不知道根的,所以我们不得不加上一个换根。
但如果涉及换根的话,相当于我们就要动态维护子节点的 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的主要内容,如果未能解决你的问题,请参考以下文章

C. Ayoub and Lost Array cf dp

CF1105C Ayoub and Lost Array

CF1105C Ayoub and Lost Array ——动态规划

git add的代码,但是不小心丢了怎么办

如何从后台弹出片段

Elasticsearch:None of the configured nodes are available