终于不颓了今天
点分。对于无根树上的路径,对于一个点(视作根)来说,要么这条路径是经过当前点,要么是存在于这个点的子树,后者交给子树做,对于前者,处理出树中所有点到达根的距离,以及存在于根的那个孩子的子树。按距离排一遍序,从大到小枚举点,同时指针从小到大枚举和它配对的点,由于枚举点的大小单调递减,所以指针前面的点肯定可以和当前点配对,从当前指针位置枚举即可。这样就相当于O(n)的复杂度。还有,要用数组+时间戳记录当前某个子树的点在指针前有多少个,记录答案的时候要去掉同一子树的配对情况。
我TM的getrt完了之后为啥点分传的还是y
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n,K; struct node { int x,y,d,next; }a[21000];int len,last[11000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } int rt,sum,tot[11000],G[11000]; bool v[11000]; void getrt(int x,int fr) { G[x]=0;tot[x]=1; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr&&v[y]==false) { getrt(y,x); G[x]=max(G[x],tot[y]); tot[x]+=tot[y]; } } G[x]=max(G[x],sum-tot[x]); if(rt==0||G[rt]>G[x])rt=x; } //-------------------------- struct zz{int bel,d;}z[11000];int zlen; bool cmp(zz z1,zz z2){return z1.d<z2.d;} void getd(int x,int fr,int bel,int d) { zlen++; z[zlen].bel=bel;z[zlen].d=d; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr&&v[y]==false)getd(y,x,bel,d+a[k].d); } } int ap[11000],tim,ti[11000]; int calc(int x) { zlen=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==false)getd(y,x,y,a[k].d); } sort(z+1,z+zlen+1,cmp); int be=1,ret=0; tim++; for(int i=zlen;i>=1;i--) { if(z[i].d<=K)ret++; for(int j=be;j<i;j++) { if(z[i].d+z[j].d<=K) { if(ti[z[j].bel]!=tim){ti[z[j].bel]=tim;ap[z[j].bel]=0;} ap[z[j].bel]++; be++; } else break; } if(i<be)ap[z[i].bel]--; ret+=min(i,be)-1-ap[z[i].bel]; } return ret; } //--------------------------- int ans; void divi(int x) { v[x]=true;ans+=calc(x); for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==false) { rt=0;sum=tot[y]; getrt(y,x); divi(rt); } } } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); while(scanf("%d%d",&n,&K)!=EOF) { if(n==0&&K==0)break; len=0;memset(last,0,sizeof(last)); int x,y,d; for(int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&d); ins(x,y,d);ins(y,x,d); } rt=0;sum=n; memset(v,false,sizeof(v)); getrt(1,0); ans=0; tim=0;memset(ti,0,sizeof(ti)); divi(rt); printf("%d ",ans); } return 0; }