恶心题
要写两个线段树还得是区间覆盖的,其中一个是树链剖分的,另一个是维护括号序列的。
有两种边,一种是免费的,一种是有代价的,每次取最短路,树形结构大约就不要退流了吧。
每次树链剖分找最短边,括号序列维护距离。
#include <cstdio>
#include <cstdlib>
#include <cstring>
const long long oo=1073741819;
const int maxn=200000,maxr=524288,maxl=500000;
struct sort {int o,d,i;}a[maxn];
int ans,n,m,tail[maxn],b[2][maxr],c[maxr],p[maxn],ss,next[maxl],sora[maxl],low[maxl],lim[maxl],m1,s,s1,l[maxn],r[maxn],high,st[maxn],rt[maxn],rs[maxn],f[maxn],o[maxn],ll[maxr],rr[maxr];
long long flow[maxn],t[2][maxr],dep[maxr],max[maxn],maxi[maxn],sum,d[2][maxr],lx[maxr],q[maxr],v[maxr];
void origin()
{
int i;
for (i=0;i<=n;i++) tail[i]=i;ss=n;
for (m1=1,high=0;m1<=n+2;m1<<=1,high++) ;
}
void link(int x,int y,int z,int k)
{
ss++,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,low[ss]=z,lim[ss]=k;
}
void dfs(int x)
{
int i,ne;
l[x]=oo,r[x]=-oo;
if (next[x]==0) l[x]=r[x]=++s,b[0][s+m1]=x;
for (i=x;next[i]!=0;) {
i=next[i],ne=sora[i];
dfs(ne);
if (l[ne]<l[x]) l[x]=l[ne];
if (r[ne]>r[x]) r[x]=r[ne];
}
}
int minc(int e,int x,int y) {return (d[e][x]<d[e][y]) ? b[e][x] : b[e][y];}
int min(int e,int x,int y) {return (d[e][x]<d[e][y]) ? d[e][x] : d[e][y];}
void pushdown(int e,int x)
{
int xx,lson,rson;
for (int i=high;i>=0;i--) {
xx=x>>i;
if (t[xx]) {
lson=(xx<<1),rson=lson+1;
d[e][lson]+=t[e][xx],d[e][rson]+=t[e][xx];
t[e][lson]+=t[e][xx],t[e][rson]+=t[e][xx];
t[e][xx]=0;
}
}
}
int ask(int e,int l,int r)
{
int ll,rr,mini;
l+=m1-1,r+=m1+1;
ll=l>>1,rr=r>>1;
pushdown(e,ll),pushdown(e,rr);
for (sum=oo;!(1==(l^r));l>>=1,r>>=1) {
if (0==(l&1)) if (d[e][l+1]<sum) sum=d[e][l+1],mini=b[e][l+1];
if (1==(r&1)) if (d[e][r-1]<sum) sum=d[e][r-1],mini=b[e][r-1];
}
return mini;
}
void updata(int e,int x) {for (;x;x>>=1) b[e][x]=minc(e,x<<1,(x<<1)+1),d[e][x]=min(e,x<<1,(x<<1)+1);}
void change(int e,int l,int r,int k)
{
l+=m1-1,r+=m1+1;
int ll=l>>1,rr=r>>1;
pushdown(e,ll),pushdown(e,rr);
for (;!(1==(l^r));l>>=1,r>>=1) {
if (0==(l&1)) d[e][l+1]+=k,t[e][l+1]+=k;
if (1==(r&1)) d[e][r-1]+=k,t[e][r-1]+=k;
}
updata(e,ll),updata(e,rr);
}
void bfs(int s)
{
int h,r,ne,i,na;
h=r=0,st[r=1]=s,dep[s]=0;
for (;h<r;) {
ne=st[++h];
for (i=ne;next[i]!=0;) {
i=next[i],na=sora[i];
dep[na]=dep[ne]+1,rt[na]=ne,rs[na]=i,st[++r]=na;
}
}
memset(max,129,sizeof(max));
for (i=r;i>=1;i--) {
ne=st[i],na=rt[ne];
f[na]+=++f[ne];
if (f[ne]>max[na]) max[na]=f[ne],maxi[na]=ne;
if (maxi[ne]!=0) {
na=maxi[ne];
if (o[na]==0) o[na]=++s1;
o[ne]=o[na];
}
}
}
int cmp(const void *i,const void *j)
{
sort p=*(sort *)i,q=*(sort *)j;
if (p.o!=q.o) return p.o-q.o;
return p.d-q.d;
}
void ori()
{
int i,j;
for (i=1;i<=n;i++) a[i].o=o[i],a[i].d=dep[i],a[i].i=i;
qsort(a+1,n,sizeof(a[1]),cmp);
for (i=1;(0==a[i].o);i++) ;j=i;
for (s1=0;i<=n;i++) {
++s1;
if (a[i].o!=a[i-1].o) ll[a[i].o]=s1,lx[a[i].o]=a[i].i,rr[a[i-1].o]=s1-1;
p[a[i].i]=s1;b[1][s1+m1]=a[i].i;q[a[i].i]=i;
}
rr[a[n].o]=s1;
change(1,p[1],p[1],oo+oo);
for (i=j;i<=n;i++) if (a[i].i!=1) change(1,p[a[i].i],p[a[i].i],low[rs[a[i].i]]-oo);
for (i=1;i<j;i++) flow[a[i].i]=low[rs[a[i].i]];
}
int search(int x,int &z)
{
int min=oo,mini=0,cos;
for (;x!=1;) {
if (p[x]) {
cos=ask(1,ll[a[q[x]].o],p[x]);
if (sum<min) min=sum,mini=cos;
x=rt[lx[a[q[x]].o]];
}
else {
if (flow[x]<min) min=flow[x],mini=x;
x=rt[x];
}
}
z=min;
return mini;
}
void sign(int x,int k)
{
for (;x!=1;) {
if (p[x]) {
change(1,ll[a[q[x]].o],p[x],k),x=rt[lx[a[q[x]].o]];
}
else {
flow[x]+=k;
x=rt[x];
}
}
}
void init()
{
int i,x,y,z,k,sum1;
scanf("%d%d\n",&n,&m);n++;
origin();
for (i=1;i<=n-1;i++) scanf("%d%d%d%d",&x,&y,&z,&k),link(x+1,y+1,z,k);
s1=0,dfs(1),bfs(1);
for (i=1;i<=m1+m1;i++) d[0][i]=d[1][i]=oo;
ori();
for (i=1;i<=n;i++) if (b[0][l[i]+m1]==i) change(0,l[i],l[i],-oo);
ans=sum1=z=0,rt[1]=1;
for (;;) {
// printf("%d %d\n",ans,sum1);
x=ask(0,1,n);sum1=sum;
if (sum1>=oo) break;
y=search(x,z);
if (sum1*z<=m) m-=sum1*z,ans+=z;
else {ans+=m/sum1,m=0;break;}
if (v[y]) change(0,l[y],r[y],oo),sign(x,-z);
else {
v[y]=1;
change(0,l[y],r[y],1);
if (z) sign(x,-z);
if (p[y]) {change(1,p[y],p[y],lim[rs[y]]-low[rs[y]]);}
else flow[y]=lim[rs[y]]-z;
}
}
printf("%d\n",ans);
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
init();
return 0;
}