树上路径统计,点分治解决。
统计一段区间,naive地用了set解决,这样的复杂度是O(nlog^2n)的
考场代码出了个问题,统计答案时找到了之前的最优答案,但是没有加上新的一段,导致60分
#include<iostream> #include<cstdio> #include<set> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN = 100005; struct Edge{ int next,to,w; }e[MAXN<<1]; int ecnt,head[MAXN]; inline void add(int x,int y,int w){ e[++ecnt].next = head[x]; e[ecnt].to = y; e[ecnt].w = w; head[x] = ecnt; } int n,L,R; bool vis[MAXN]; int siz[MAXN]; void getsiz(int x,int pre){ siz[x]=1; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(v==pre||vis[v]) continue; getsiz(v,x); siz[x]+=siz[v]; } } int mn,root; void getroot(int x,int pre,int tot){ int mx=0; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(v==pre||vis[v]) continue; mx=max(mx,siz[v]); getroot(v,x,tot); } mx=max(mx,tot-siz[x]); if(mx<mn) root=x,mn=mx; } set<int> se; int s[MAXN]; void dfs(int x,int pre,int dis){ if(dis>R) return;// s[++s[0]]=dis; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(v==pre||vis[v]) continue; dfs(v,x,dis+e[i].w); } } int ans=1<<30; void dac(int x){ mn=n; getsiz(x,-1); getroot(x,-1,siz[x]); int u=root;vis[u]=1; se.clear(); se.insert(1<<30); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(vis[v]) continue; s[0]=0;dfs(v,u,e[i].w); for(int j=s[0];j>=1;j--){ int tmp=*se.lower_bound(L-s[j]); tmp+=s[j]; if(tmp<ans&&tmp<=R&&tmp>=L) ans=tmp; } for(int j=s[0];j>=1;j--){ if(s[j]<ans&&s[j]<=R&&s[j]>=L) ans=s[j]; se.insert(s[j]); } } for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(!vis[v]) dac(v); } } int main(){ n=rd();L=rd();R=rd(); int x,y,w; for(int i=1;i<=n-1;i++){ x=rd();y=rd();w=rd(); add(x,y,w);add(y,x,w); } dac(1); if(ans==1<<30) cout<<-1; else cout<<ans; return 0; }