【边分治】Kuala Lumpur 2008

该博客介绍了如何解决一类特定的树上路径问题:找到路径使得第一维上的和小于给定值m,同时最大化第二维的和。通过采用拆边策略,将原问题转化为二叉树结构,然后利用加点方式表示节点的左儿子和右兄弟,以此简化问题并方便求解。尽管涉及数组和BFS操作,但整个过程描述流畅。
摘要由CSDN通过智能技术生成

求树上路径第一维之和小于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;
}


['Asia/Aden', 'Asia/Almaty', 'Asia/Amman', 'Asia/Anadyr', 'Asia/Aqtau', 'Asia/Aqtobe', 'Asia/Ashgabat', 'Asia/Ashkhabad', 'Asia/Atyrau', 'Asia/Baghdad', 'Asia/Bahrain', 'Asia/Baku', 'Asia/Bangkok', 'Asia/Barnaul', 'Asia/Beirut', 'Asia/Bishkek', 'Asia/Brunei', 'Asia/Calcutta', 'Asia/Chita', 'Asia/Choibalsan', 'Asia/Chongqing', 'Asia/Chungking', 'Asia/Colombo', 'Asia/Dacca', 'Asia/Damascus', 'Asia/Dhaka', 'Asia/Dili', 'Asia/Dubai', 'Asia/Dushanbe', 'Asia/Famagusta', 'Asia/Gaza', 'Asia/Harbin', 'Asia/Hebron', 'Asia/Ho_Chi_Minh', 'Asia/Hong_Kong', 'Asia/Hovd', 'Asia/Irkutsk', 'Asia/Istanbul', 'Asia/Jakarta', 'Asia/Jayapura', 'Asia/Jerusalem', 'Asia/Kabul', 'Asia/Kamchatka', 'Asia/Karachi', 'Asia/Kashgar', 'Asia/Kathmandu', 'Asia/Katmandu', 'Asia/Khandyga', 'Asia/Kolkata', 'Asia/Krasnoyarsk', 'Asia/Kuala_Lumpur', 'Asia/Kuching', 'Asia/Kuwait', 'Asia/Macao', 'Asia/Macau', 'Asia/Magadan', 'Asia/Makassar', 'Asia/Manila', 'Asia/Muscat', 'Asia/Nicosia', 'Asia/Novokuznetsk', 'Asia/Novosibirsk', 'Asia/Omsk', 'Asia/Oral', 'Asia/Phnom_Penh', 'Asia/Pontianak', 'Asia/Pyongyang', 'Asia/Qatar', 'Asia/Qostanay', 'Asia/Qyzylorda', 'Asia/Rangoon', 'Asia/Riyadh', 'Asia/Saigon', 'Asia/Sakhalin', 'Asia/Samarkand', 'Asia/Seoul', 'Asia/Shanghai', 'Asia/Singapore', 'Asia/Srednekolymsk', 'Asia/Taipei', 'Asia/Tashkent', 'Asia/Tbilisi', 'Asia/Tehran', 'Asia/Tel_Aviv', 'Asia/Thimbu', 'Asia/Thimphu', 'Asia/Tokyo', 'Asia/Tomsk', 'Asia/Ujung_Pandang', 'Asia/Ulaanbaatar', 'Asia/Ulan_Bator', 'Asia/Urumqi', 'Asia/Ust-Nera', 'Asia/Vientiane', 'Asia/Vladivostok', 'Asia/Yakutsk', 'Asia/Yangon', 'Asia/Yekaterinburg', 'Asia/Yerevan']
最新发布
02-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值