数据结构好题#2.1

原题链接

3h切掉,常数很低,是最优解前十。

——————————分割线——————————

这本是一道点分治裸题,然后我不是什么有实力的人,所以认定这是一道对自己提升很大的题,即便是板子,能靠自己一点点写出来也对个人有很大提升

据说本题还有dsu on tree的做法,回头再看吧

#include<bits/stdc++.h>
using namespace std;
#define re register
#define fo1(l,r) for(re int i=l;i<=r;++i)
#define fo2(l,r) for(re int j=l;j<=r;++j)
#define fo3(l,r) for(re int k=l;k<=r;++k)
#define fo4(l,r) for(re int tt=l;tt<=r;++tt)
#define inf 0x3f3f3f3f
#define INF 0x7fffffffffffffff
#define LL long long
#define itn int
#define getchar() (it==is&&(is=(it=C)+fread(C,1,1<<21,stdin),it==is)?EOF:*it++)
char C[1<<21],*it=C,*is=C;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-'){f=-1;};ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
    return x*f;
}
const itn N=4e4+10;
int n,k,st;
struct node
{
	int to,last,dis;
}x[N<<1];
int h[N],ss;
inline void yadd(int xx,int yy,int zz)
{
	x[++ss].to=yy;
	x[ss].dis=zz;
	x[ss].last=h[xx];
	h[xx]=ss;
	return;
}
LL minn,bh;
LL siz[N];
bitset<N> pd;
vector<pair<LL,int> > v;
#define d(x) v[x].first
#define b(x) v[x].second
LL cnt[N];
LL ANS;
inline LL max2(LL xx,LL yy)
{
	return xx>yy?xx:yy;
}
inline bool cmp(pair<LL,int> xx,pair<LL,int> yy)
{
	return xx.first<yy.first;
}
inline void dfs(int now,int fa,int sum)//求子树大小与重心 
{
	siz[now]=1;
	LL ans=-1;
	for(re int i=h[now],go;i;i=x[i].last)
	{
		go=x[i].to;
		if(go!=fa && pd[go]==0)
		{
			dfs(go,now,sum);
			siz[now]+=siz[go];
			ans=max2(ans,siz[go]);
		}
	}
	ans=max2(ans,sum-siz[now]);
	if(ans<minn)
	{
		minn=ans;bh=now;
	}
	return;
}
inline void ydfs(int now,int fa,LL vv,int ty)//求d与b 
{
	for(re int i=h[now],go;i;i=x[i].last)
	{
		go=x[i].to;
		if(pd[go]==0 && go!=fa)
		{
//			cout<<"后辈"<<go<<endl;
			v.push_back(make_pair(vv+x[i].dis,ty));
			++cnt[ty];
			ydfs(go,now,vv+x[i].dis,ty);
		}
	}
	return;
}
inline void Dfs(int now,int sum)
{
	
	//第一步找重心,重心为bh 
	minn=inf;
	dfs(now,-1,sum);
	int st=bh;
	//第二步以重心为根,建立v数组
	
//	cout<<"当前以"<<st<<"为根,大小为"<<sum<<endl; 
	v.clear();
	v.push_back(make_pair(0,1));
	cnt[1]=1;
	int tyy=1;
	for(re int i=h[st],go;i;i=x[i].last)
	{
		go=x[i].to;
		if(pd[go]==0)
		{
//			cout<<"儿子"<<go<<endl; 
			v.push_back(make_pair(x[i].dis,++tyy));
			cnt[tyy]=1;
			ydfs(go,st,x[i].dis,tyy);
		}
	}
	//第三步双指针统计答案
	sort(v.begin(),v.end(),cmp);
//	if(!v.empty())
//	{
//		fo1(0,v.size()-1)
//			cout<<d(i)<<" ";
//		cout<<endl;
//		fo1(0,v.size()-1)
//			cout<<b(i)<<" ";
//		cout<<endl;
//		fo1(1,tyy)
//			cout<<cnt[tyy]<<" ";
//		cout<<endl;
//	}
	
	int ll=0,rr=v.size()-1;
	LL ans=0; 
	--cnt[b(0)];
	while(ll<rr)
	{
		while(d(rr)+d(ll)>k)
		{
			--cnt[b(rr)];
			--rr;
			if(rr==ll)
				break;
		}
		if(rr!=ll)
		{
			ans+=rr-ll-cnt[b(ll)];
			++ll;
			--cnt[b(ll)];
		}
	}
//	cout<<"统计答案为"<<ans<<endl;
	ANS+=ans;
	//第四步删点递归
	pd[st]=1;
	for(re itn i=h[st],go;i;i=x[i].last)
	{
		go=x[i].to;
		if(pd[go]==0)
		{
//			cout<<"删掉节点"<<st<<"后进入节点"<<go<<endl;
			Dfs(go,siz[go]);
		}
	}
	return;
}
int main()
{
	n=read();
	fo1(1,n-1)
	{
		int ls1=read(),ls2=read(),ls3=read();yadd(ls1,ls2,ls3);yadd(ls2,ls1,ls3);
	}
	k=read();
	Dfs(1,n);
	printf("%lld",ANS);
	return 0;
}

  

posted @ 2023-06-06 21:37  小鱼儿吼吼  阅读(20)  评论(0)    收藏  举报