CF150E Freezing with Style

题面

英文题面

题意:给定一颗带边权的树,求一条边数在 [L,R][L,R] 之间的路径,并使得路径上边权的中位数最大。输出一条可行路径的两个端点。有两个中位数时取较大的那个。\(n \leq 10^5\)

题解:对于中位数的题,常见的套路是二分答案\(w\),将小于\(w\)的数定为-1或0,将大于等于\(w\)的数定为1,然后就能方便地进行一些操作。那么对于本题,二分答案\(w\)后,check时我们就只需要找到是否存在一条路径,它的边权和\(\geq 0\)

考虑用点分治做。因为我们有\(L,R\)的限制,所以需要记一个\(a_i\)表示与分治中心距离为\(i\)的边权和的最大值。那么一个显然的做法就是大力搞棵线段树。但考虑到每个点在单次分治时需要查一次线段树,修改一次线段树,还要进行build操作,那么总复杂度就成了三个log,常数也很大,很难通过。考虑优化。

我们在进入分治中心的一个儿子查询时,可以考虑换一种查询方法:记\(b_i\)表示当前这个儿子的最大值,定义与\(a_i\)类似。又因为对于每个\(i\),能对它产生贡献的是一段连续区间,且当\(i\)增大时,是个滑动窗口,那么就能用单调队列来优化这个过程。

但考虑到对于每个儿子,单调队列都要产生\(O(mxdep)\)的复杂度,这显然是不可接受的。所以,我们先将所有儿子按子树最大深度\(mxdep\)排序,这样,对于每个儿子\(x\),复杂度就是\(O(mxdep_x)\),加起来是\(O(n)\)级别的。这样,点分治的总复杂度就是\(O(nlogn)\)

最好把点分树先建出来,以避免冗余的计算。

时间复杂度:\(O(nlog^2n)\)

代码:又臭又长

#include
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
templateI read(D &res){
	res=0;register D g=1;register char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')g=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=(res<<3)+(res<<1)+(ch^48);
		ch=getchar();
	}
	res*=g;
}
const int INF=1e9+7;
vectort[101000];
struct E{
	int to,nt,w,v;
}e[202000];
#define T e[k].to
int n,m,rot,L,R,M,sn,head[101000],tot,X,Y,W;
int siz[101000],vis[101000],dep[101000],mx[101000],val[101000],a[101000],pa[101000],b[101000],pb[101000],q[101000],hed,tal,N,maxi,root;
int A,B;
vectorson;
I add(int x,int y,int w){
	e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].w=w;
}
I findroot(int x,int fa){
	siz[x]=1;mx[x]=0;
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(T==fa||vis[T])continue;
		findroot(T,x);
		siz[x]+=siz[T];mx[x]=max(mx[x],siz[T]);
	}
	mx[x]=max(mx[x],N-siz[x]);
	if(mx[x]b[dep[x]])b[dep[x]]=val[x],pb[dep[x]]=x;
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(T==fa||vis[T])continue;
		D_3(T,x);
	}
}
I conquer(int x){
	if(sn)return;
//	cout<<"Conq:"<=0)sn=1,A=pa[q[hed]],B=pb[1];
		F(i,2,mx[d]){
			while(hed<=tal&&q[hed]+i>R)hed++;
			if(L-i<=maxi&&L>=i&&a[L-i]>-INF){
				while(hed<=tal&&a[q[tal]]<=a[L-i])tal--;
				q[++tal]=L-i;
			}
			if(hed<=tal&&b[i]+a[q[hed]]>=0)sn=1,A=pa[q[hed]],B=pb[i];
		}
		F(i,1,mx[d]){
			if(a[i]>1;
	if(ck(mid))dichotomize(mid,r);
	else dichotomize(l,mid-1);
	//,cout<<"!"<

你可能感兴趣的:(CF150E Freezing with Style)