【边分治】Kuala Lumpur 2008

来源:互联网 发布:袁隆平杂交水稻数据 编辑:程序博客网 时间:2024/05/20 16:41

求树上路径第一维之和小于m,第二维之和最大

拆边,每个点的儿子用加点的方式左儿子右兄弟的表示,这样就是一棵二叉树了

虽然数组和bfs很多,但是写得很顺...

#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>const int maxn=200000,maxm=500000,oo=1073741819;using namespace std;struct sta{    int rt,d,l;}A[maxn];int tail[maxn],next[maxm],sora[maxm],id[maxm];int l[maxm],r[maxm],D[maxm],L[maxm],fl[maxm],n,ss,tot,w_time;int v[maxn],T[maxn],u[2][maxn],st[maxn],sd[maxn],sl[maxn];int size[maxn],rt[maxn],ry[maxn],last[maxn];int ans,M,t;void origin(){    tot=0;    ss=n+n;    for (int i=1;i<=ss;i++) tail[i]=i,next[i]=0;}void link(int x,int y,int d,int ll){    ++tot;    ++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0,id[ss]=tot;    ++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0,id[ss]=tot;    l[tot]=x,r[tot]=y,D[tot]=d,L[tot]=ll;}void bfs1(){    int h,r,ne,na;    for (int i=1;i<=n;i++) v[i]=0;    h=r=0;    st[r=1]=1,v[1]=1;    for (;h<r;) {        ne=st[++h];        for (int i=ne;next[i];) {            i=next[i],na=sora[i];            if (!v[na]) {                st[++r]=na;                A[na].rt=ne,A[na].d=D[id[i]],A[na].l=L[id[i]];                v[na]=1;            }        }    }//    cout<<r<<endl;    origin();    for (int i=1;i<=n;i++) last[i]=0;    int cnt=n;    for (int i=r;i>=2;i--) {        ne=st[i];        na=A[ne].rt;        if (!last[na]) {            last[na]=++cnt;            link(na,last[na],0,0);        }        else {            ++cnt;            link(last[na],cnt,0,0);            last[na]=cnt;        }        link(last[na],ne,A[ne].d,A[ne].l);    }    n=cnt;}int bfs2(int s){    int h,r,ne,na;    ++w_time;    h=r=0;    st[r=1]=s,T[s]=w_time,size[s]=0;    for (;h<r;) {        ne=st[++h];        for (int i=ne;next[i];) {            i=next[i],na=sora[i];            if (T[na]!=w_time && fl[id[i]]) {                T[na]=w_time,size[na]=0,rt[na]=ne,ry[na]=id[i];                st[++r]=na;            }        }    }    int Mins=oo,Mini=0;    for (int i=r;i>=2;i--) {        ne=st[i];        size[ne]++;        int tmp=max(size[ne],r-size[ne]);        if (tmp<Mins) {            Mins=tmp,Mini=ry[ne];        }        size[rt[ne]]+=size[ne];    }    return Mini;}int bfs3(int s){    int h,r,ne,na;    ++w_time;    h=r=0;    st[r=1]=s,T[s]=w_time,sd[s]=0,sl[s]=0;    for (;h<r;) {        ne=st[++h];        for (int i=ne;next[i];) {            i=next[i],na=sora[i];            if (T[na]!=w_time && fl[id[i]]) {                T[na]=w_time,sd[na]=sd[ne]+D[id[i]],sl[na]=sl[ne]+L[id[i]];                st[++r]=na;            }        }    }    return r;}bool cmp1(int i,int j){    return sd[i]>sd[j];}bool cmp2(int i,int j){    return sd[i]<sd[j];}void calc(int s){    int G=bfs2(s);    if (!G) return ;    fl[G]=0;    int h[2];    h[0]=bfs3(l[G]);    for (int i=1;i<=h[0];i++) u[0][i]=st[i];    h[1]=bfs3(r[G]);    for (int i=1;i<=h[1];i++) u[1][i]=st[i];    sort(u[0]+1,u[0]+h[0]+1,cmp1);    sort(u[1]+1,u[1]+h[1]+1,cmp2);    for (int i=1,j=1,Max=-oo;i<=h[0];i++) {        for (;(j<=h[1]) && (sd[u[0][i]]+sd[u[1][j]]+D[G]<=M);++j) Max=max(Max,sl[u[1][j]]);        int tmp=sl[u[0][i]]+Max+L[G];        ans=max(ans,tmp);    }    calc(l[G]);    calc(r[G]);}int main(){    scanf("%d",&t);    for (int test=1;t;t--,test++) {        printf("Case %d: ",test);        scanf("%d%d",&n,&M);        origin();        for (int i=1;i<=n-1;i++) {            int x,y,d,l;            scanf("%d%d%d%d",&x,&y,&d,&l);            link(x,y,d,l);        }        bfs1();        for (int i=1;i<=tot;i++) fl[i]=1;        for (int i=1;i<=n;i++) T[i]=0;        w_time=0;        ans=0;        calc(1);        printf("%d\n",ans);    }    return 0;}


原创粉丝点击