题意:给定一棵有边权的树  和一个k    问最少多少边(连续)的长度和为k   

 

解法一(也是我一开始的写法)

遍历所有的边  并且给每个边设置一个标记属于某课子树 然后用lowerbound和upperbound找到满足的边 遍历一遍统计答案  用了4s

 

解法二(只用2s)

边数太多的时候上面的算法复杂度接近 n^2logn QAQ

可以做成3n的 并且每一棵每一棵子树得统计答案和更新子树情况 (先统计  后更新)   就可以避免统计的边不是最短路的情况


P4149 [IOI2011]Race  点分治_#includeP4149 [IOI2011]Race  点分治_c++_02


#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v) memset(A,v,sizeof A)
//////////////////////////////////////
const int N=2e5+10;
int n,m,cnt,d[N],head[N],pos,siz[N],sum,x,y,z,ans,vis[N],root,maxson[N],k,temp[N*10];
struct Edge{int to,nex,v;}edge[N<<1];
void add(int a,int b,int c){edge[++pos]=(Edge){b,head[a],c};head[a]=pos;}
struct bian
{
int num,v,belong;
bool operator <(const bian &b)const{return v<b.v;}
}s[N];
void getroot(int x,int fa)
{
siz[x]=1;maxson[x]=0;
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v]||v==fa)continue;
getroot(v,x);siz[x]+=siz[v];
maxson[x]=max(maxson[x],siz[v]);
}
maxson[x]=max(maxson[x],sum-siz[x]);
if(maxson[x]<maxson[root])root=x;
}
void getdis(int x,int fa,int val,int num)
{
if(val>k)return ;
temp[val]=min(temp[val],num);
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v]||v==fa)continue;
getdis(v,x,val+edge[i].v,num+1);
}
}
void init(int x,int fa,int val)
{
if(val>k)return ;
temp[val]=1e9 ;
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v]||v==fa)continue;
init(v,x,edge[i].v+val);
}
}
void upans(int x,int fa,int val,int num)
{
if(val>k)return ;
ans=min(ans,temp[k-val]+num);
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v]||v==fa)continue;
upans(v,x,val+edge[i].v,num+1);
}
}
void calc(int x)
{
temp[0]=0;
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v])continue;
upans(v,x,edge[i].v,1);
getdis(v,x,edge[i].v,1);
}
init(x,0,0);
}
void solve(int x)
{
vis[x]=1;
calc(x);
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v])continue;
root=0;sum=siz[v];
getroot(v,x);
solve(root);
}
}
int main()
{
scanf("%d%d",&n,&k);
rep(i,1,n-1)
scanf("%d%d%d",&x,&y,&z),x++,y++,add(x,y,z),add(y,x,z);
rep(i,0,k)temp[i]=1e9;
ans=1e9;
sum=maxson[0]=n;
root=0;
getroot(1,0);

solve(root);
if(ans==1e9)printf("-1\n");
else printf("%d",ans);
}

View Code