数据结构好题#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;
}

浙公网安备 33010602011771号