点分治模板一改一改的水法水过了。。。
查看原帖
点分治模板一改一改的水法水过了。。。
52915
Ajwallet楼主2021/2/22 12:06

众所周知,点分治模板一是询问是否有树上路径长度为KK 而这道题问路径长度为KK的最小边数

所以在我用其中一种正解(桶+点分治 O(nlogn)O(n\log n) ) 过了这题后

我寻思着这两题这么像(看起来),可不可以在判断合法的那里改成找最优的水过去

因为模板那道题只是问是否存在,而这道题是要求最优,所以不能匹配到一组后就退出了,而应找出其它的合法的

对于一种不合法的情况,即revl,revrrev_l,rev_r属于一种子树是肯定要排除掉的,模板那道题是判断revrrev_rrevr1rev_{r-1}是否相同来调整的。我想着对于这道题,应该是要尽量找到更多的组,所以就弄了个失配数组failfail,在匹配失败的时候让rr跳,复杂度很玄学,但是在洛谷能过。。。

但这种写法显然是错误的,在ybtOjybtOj上被更强的数据hack了。。。如果可以的话,建议加强下数据。。。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
#define N 200010
using namespace std;int n,l[N],k,tot,u,v,m;
struct node{int next,to;LL w;}e[N<<1];
LL w,K;
inline void add(int u,int v,LL w){e[++tot]=(node){l[u],v,w};l[u]=tot;return;}
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
bool vis[N];
int siz[N],f[N],sum,rt,len[N];
inline void Getrt(int x,int fa=0)
{
	siz[x]=1;f[x]=0;
	for(register int i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa||vis[y]) continue;
		Getrt(y,x);siz[x]+=siz[y];f[x]=max(f[x],siz[y]);
	}
	f[x]=max(f[x],sum-siz[x]);if(f[x]<f[rt]) rt=x;return;
}
LL dis[N],rev[N];int cnt,a[N],belong[N];
inline void Getdis(int x,int fa=0,int which=0)
{
	rev[++cnt]=x;belong[x]=which;
	for(register int i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa||vis[y]) continue;
		dis[y]=dis[x]+e[i].w;len[y]=len[x]+1;
		Getdis(y,x,which);
	}return;
}
int ans=0x3f3f3f3f,fail[N];
inline bool cmp(int x,int y){return dis[x]<dis[y];}
inline void Doit(int x)
{
	cnt=1;rev[cnt]=x;dis[x]=0;belong[x]=x;len[x]=0;
	for(register int i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(vis[y]) continue;
		dis[y]=e[i].w;len[y]=1;
		Getdis(y,x,y);
	}
	sort(rev+1,rev+1+cnt,cmp);
	int l=1,r=cnt;fail[cnt]=cnt+1;
	for(register int i=cnt-1;i;i--) fail[i]=(belong[rev[i]]==belong[rev[i+1]])?fail[i+1]:i+1;
	for(;l<r;++l)
	{
		for(;l<r&&dis[rev[r-1]]+dis[rev[l]]>=K;r--);
		if(belong[rev[l]]==belong[rev[r]]) r=fail[r];
		while(r<=cnt&&dis[rev[l]]+dis[rev[r]]==K) 
		{
			if(belong[rev[l]]!=belong[rev[r]]) ans=min(ans,len[rev[l]]+len[rev[r]]);
			r=fail[r];
		}
	}
	return;
}
inline void Solve(int x)
{
	vis[x]=1;Doit(x);
	for(register int i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(vis[y]) continue;
		f[rt=0]=n;sum=siz[y];
		Getrt(y,x);Solve(rt);
	}
	return;
}
signed main()
{
	n=read();K=read();
	for(register int i=1;i<n;i++) u=read()+1,v=read()+1,w=read(),add(u,v,w),add(v,u,w);
	f[0]=sum=n;Getrt(1);Solve(rt);
	if(ans==0x3f3f3f3f) puts("-1");else
	printf("%d",ans);
}
2021/2/22 12:06
加载中...