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