【邊分治】Kuala Lumpur 2008

求樹上路徑第一維之和小於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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章