bzoj3124: [Sdoi2013]直径
第一问应该没人不会吧。
然后第二问,可以意识(证明也可以)到这些边一定是连续的,我一开始的想法是枚举区间,但是这个是平方级别的不兹瓷
对于一段区间假如它左右端点查找除直径外最大值的和加上区间的值等于直径,而我对于这个的想法是,这一段的边可能成为答案,但是我没有很好的意识到(lj做题全凭感觉),非这段区间的边必然不能成为答案。这样一个for就可以了。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; struct node { int x,y,next;LL d; }a[410000];int len,last[210000]; void ins(int x,int y,LL d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; }//init int L,R;LL mxdis; void getL(int x,int fr,LL dis) { if(dis>mxdis) L=x, mxdis=dis; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr) getL(y,x,dis+a[k].d); } } void getR(int x,int fr,LL dis) { if(dis>mxdis) R=x, mxdis=dis; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr) getR(y,x,dis+a[k].d); } } //--------------取得树的直径------------------------- LL andis;bool v[210000]; void getfarther(int x,int fr,LL dis) { if(dis>andis)andis=dis; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr&&v[y]==false) getfarther(y,x,dis+a[k].d); } } bool bk; int plen,p[210000];LL d[210000]; void dfs(int x,int fr) { if(bk==true)return ; if(x==R) { bk=true; int l=1,r=plen;LL s; s=0; for(int i=2;i<plen;i++) { s+=d[i]; andis=0;getfarther(p[i],0,0); if(andis+s==mxdis){r=i;break;} } s=0; for(int i=plen-1;i>=2;i--) { s+=d[i+1]; andis=0;getfarther(p[i],0,0); if(andis+s==mxdis){l=i;break;} } if(l>r)l=r; printf("%d\n",r-l); return ; } for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr) { d[++plen]=a[k].d; p[plen]=y; v[y]=true; dfs(y,x); v[y]=false; p[plen]=0; d[plen--]=0; } } } int main() { freopen("data.in","r",stdin); freopen("1.out","w",stdout); int n,x,y;LL d; scanf("%d",&n); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { scanf("%d%d%lld",&x,&y,&d); ins(x,y,d);ins(y,x,d); } mxdis=0;getL(1,0,0); mxdis=0;getR(L,0,0); printf("%lld\n",mxdis); bk=false; memset(v,false,sizeof(v));v[L]=true; plen=0;p[++plen]=L; dfs(L,0); return 0; }
pain and happy in the cruel world.