IOI2022 无线电信号塔

询问实际上是求类笛卡尔树上的叶子结点个数,因为祖先一定无法与后代通信

发现如果两个叶子 \(u,v\)\(\text{LCA(u,v)}\) 的某一祖先 \(p\) 进行通信,那么 \(p\) 的祖先也一定能通信,保证两两能通信的关键就是一棵对于所有关键点的虚树,由于关键点之间并不存在祖先后代关系,因此笛卡尔树上的虚树大小一定是二倍叶子数 \(-1\)

求虚树大小是不好求的,但可以感受到虚树上的非叶子性质是很好的,记

\[time(u)=H_u-\max(\min\{Subtree(ls_u)\},min\{Subtree(rs_u)\}) \]

也即 \(u\) 的子树内可以选出两个信号塔通信的最小 \(D\),为了最大化答案,一定会贪心地选择所有满足 \(time(u)\ge D\) 的子树根放到虚树上,用一个主席树就可以求出

然而求的答案可能出现选出的信号塔在区间外的情况,但是因为是在笛卡尔树上,所以只会在边界出现,同样可以在主席树上二分实现

点击查看代码
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,h[N],dif[N],tmp[N],lis;
int lson[N],rson[N],tree[N];
vector<int>vec[N];
void chkmin(int&x,int y){x>y?x=y:x;}
namespace SGT{
#define mid ((l+r)>>1)
	struct Data{int ls,rs,Sum;}tr[N<<5];int rt[N],tot;
	void Copy(int&k){tr[++tot]=tr[k];k=tot;}
	void Modify(int&k,int l,int r,int x){
		Copy(k);tr[k].Sum++;if(l==r)return;
		x<=mid?Modify(tr[k].ls,l,mid,x):Modify(tr[k].rs,mid+1,r,x);
	}
	int Query(int k,int l,int r,int x,int y){
		if(!k||l>y||r<x||x>y)return 0;
		if(l>=x&&r<=y)return tr[k].Sum;
		if(y<=mid)return Query(tr[k].ls,l,mid,x,y);
		if(mid<x)return Query(tr[k].rs,mid+1,r,x,y);
		return Query(tr[k].ls,l,mid,x,y)+Query(tr[k].rs,mid+1,r,x,y);
	}
	int BoundL(int k,int l,int r,int x,int y){
		int ret=-1;
		if(!k)return max(x,l);
		if(tr[k].Sum==r-l+1)return ret;
		if(x<=mid)ret=BoundL(tr[k].ls,l,mid,x,y);
		if(ret==-1&&mid<y)ret=BoundL(tr[k].rs,mid+1,r,x,y);
		return ret;
	}
	int BoundR(int k,int l,int r,int x,int y){
		int ret=-1;
		if(!k)return min(y,r);
		if(tr[k].Sum==r-l+1)return ret;
		if(mid<y)ret=BoundR(tr[k].rs,mid+1,r,x,y);
		if(ret==-1&&x<=mid)ret=BoundR(tr[k].ls,l,mid,x,y);
		return ret;
	}
}
using namespace SGT;
namespace Sparse_Table{
	int Max[18][N],Min[18][N],lg[N];
	int chkmax(int x,int y){return h[x]>h[y]?x:y;}
	void Init(){
		for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
		for(int i=1;i<=n;i++)Min[0][i]=h[Max[0][i]=i];
		for(int j=1;j<=lg[n];j++)
			for(int i=1;i+(1<<j)-1<=n;i++){
				Min[j][i]=min(Min[j-1][i],Min[j-1][i+(1<<(j-1))]);
				Max[j][i]=chkmax(Max[j-1][i],Max[j-1][i+(1<<(j-1))]);
			}
	}
	int AskMax(int l,int r){
		int k=lg[r-l+1];
		return chkmax(Max[k][l],Max[k][r-(1<<k)+1]);
	}
	int AskMin(int l,int r){
		int k=lg[r-l+1];
		if(!(r-l+1))return 1e9+1;
		return min(Min[k][l],Min[k][r-(1<<k)+1]);
	}
}
using namespace Sparse_Table;
int Cartesian(int l,int r){
	int Mid=AskMax(l,r);
	if(l<Mid)chkmin(tree[Mid],tree[lson[Mid]=Cartesian(l,Mid-1)]);
	if(Mid<r)chkmin(tree[Mid],tree[rson[Mid]=Cartesian(Mid+1,r)]);
	return Mid;
}
int max_towers(int l,int r,int d){
	l++;r++;
	if(l==r)return 1;
	int D=lower_bound(tmp+1,tmp+lis+1,d)-tmp-1;
	int ans=r-l+1-Query(rt[D],1,n,l,r)+1;
	int lpos=BoundL(rt[D],1,n,l,r),rpos=BoundR(rt[D],1,n,l,r);
	if((~lpos)&&(~rpos)){
		if(lpos==rpos)ans-=(h[lpos]-max(AskMin(l,lpos-1),AskMin(rpos+1,r))<d);
		else{
			ans-=(h[lpos]-AskMin(l,lpos-1)<d);
			ans-=(h[rpos]-AskMin(rpos+1,r)<d);
		}
	}
	return ans;
}
void init(int nn,vector<int>H){
	n=nn;
	for(int i=1;i<=n;i++)tree[i]=h[i]=H[i-1];
	Init();Cartesian(1,n);
	for(int i=1;i<=n;i++)dif[i]=h[i]-max(tree[lson[i]],tree[rson[i]]);
	for(int i=1;i<=n;i++)if(!lson[i]||!rson[i])dif[i]=0;
	for(int i=1;i<=n;i++)tmp[++lis]=dif[i];
	sort(tmp+1,tmp+lis+1);lis=unique(tmp+1,tmp+lis+1)-tmp-1;
	for(int i=1;i<=n;i++)
		vec[lower_bound(tmp+1,tmp+lis+1,dif[i])-tmp].emplace_back(i);
	for(int i=1;i<=lis;i++){
		rt[i]=rt[i-1];
		for(auto u:vec[i])Modify(rt[i],1,n,u);
	}
}

posted @ 2023-10-04 21:42  pidan007  阅读(24)  评论(0编辑  收藏  举报