[BZOJ3681]Arietta(可持久化线段树合并优化建图+网络流)
暴力建图显然就是S->i连1,i->j'连inf(i为第j个力度能弹出的音符),j'->T连T[j]。
由于是“某棵子树中权值在某区间内的所有点”都向某个力度连边,于是线段树优化建图。由于是在树上所以需要可持久化线段树合并。
理论上可能空间会被卡,但是实际上并不能卡掉,边数最大点都不超过100W。
相比之下不太清楚为什么网上的dsu on tree做法为什么理论上就能过(可能是常数问题?),以及不理解为什么不用普通的启发式合并而非要用轻重链剖分。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 5 using namespace std; 6 7 const int N=100010,M=1000010,inf=1e9; 8 int n,m,S,T,nd,l,r,d,t,fa[N],a[N],rt[M],ls[M],rs[M],cur[M],q[M],dis[M]; 9 int cnt=1,cnt2,h[M],to[M<<1],nxt[M<<1],fl[M<<1],h2[N],to2[N],nxt2[N]; 10 11 void add(int u,int v,int w){ 12 to[++cnt]=v; fl[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; 13 to[++cnt]=u; fl[cnt]=0; nxt[cnt]=h[v]; h[v]=cnt; 14 } 15 16 void add2(int u,int v){ to2[++cnt2]=v; nxt2[cnt2]=h2[u]; h2[u]=cnt2; } 17 18 bool bfs(){ 19 rep(i,1,nd) dis[i]=0; q[1]=S; dis[S]=1; 20 for (int st=0,ed=1; st!=ed; ){ 21 int x=q[++st]; 22 For(i,x) if (fl[i] && !dis[k=to[i]]) dis[k]=dis[x]+1,q[++ed]=k; 23 } 24 return dis[T]; 25 } 26 27 int dfs(int x,int lim){ 28 if (x==T) return lim; 29 int c=0; 30 for (int &i=cur[x],k; i; i=nxt[i]) 31 if (fl[i] && dis[k=to[i]]==dis[x]+1){ 32 int t=dfs(k,min(lim-c,fl[i])); 33 c+=t; fl[i]-=t; fl[i^1]+=t; 34 if (c==lim) return c; 35 } 36 if (!c) dis[x]=-1; 37 return c; 38 } 39 40 int dinic(){ 41 int ans=0; 42 while (bfs()){ 43 rep(i,1,nd) cur[i]=h[i]; 44 ans+=dfs(S,inf); 45 } 46 return ans; 47 } 48 49 void ins(int &x,int L,int R,int p,int k){ 50 x=++nd; 51 if (L==R){ add(k,x,inf); return; } 52 int mid=(L+R)>>1; 53 if (p<=mid) ins(ls[x],L,mid,p,k); else ins(rs[x],mid+1,R,p,k); 54 if (ls[x]) add(ls[x],x,inf); 55 if (rs[x]) add(rs[x],x,inf); 56 } 57 58 void link(int x,int L,int R,int l,int r,int k){ 59 if (!x) return; 60 if (L==l && r==R){ add(x,k,inf); return; } 61 int mid=(L+R)>>1; 62 if (r<=mid) link(ls[x],L,mid,l,r,k); 63 else if (l>mid) link(rs[x],mid+1,R,l,r,k); 64 else link(ls[x],L,mid,l,mid,k),link(rs[x],mid+1,R,mid+1,r,k); 65 } 66 67 int merge(int x,int y,int L,int R){ 68 if (!x || !y) return x+y; 69 int mid=(L+R)>>1,k=++nd; 70 if (L==R){ add(x,k,inf); add(y,k,inf); return k; } 71 ls[k]=merge(ls[x],ls[y],L,mid); 72 rs[k]=merge(rs[x],rs[y],mid+1,R); 73 if (ls[k]) add(ls[k],k,inf); 74 if (rs[k]) add(rs[k],k,inf); 75 return k; 76 } 77 78 void dfs(int x){ 79 ins(rt[x],1,n,a[x],x); 80 for (int i=h2[x],k; i; i=nxt2[i]) 81 dfs(k=to2[i]),rt[x]=merge(rt[x],rt[k],1,n); 82 } 83 84 int main(){ 85 freopen("bzoj3681.in","r",stdin); 86 freopen("bzoj3681.out","w",stdout); 87 scanf("%d%d",&n,&m); S=n+m+1; nd=T=n+m+2; 88 rep(i,2,n) scanf("%d",&fa[i]),add2(fa[i],i); 89 rep(i,1,n) scanf("%d",&a[i]),add(S,i,1); 90 dfs(1); 91 rep(i,1,m){ 92 scanf("%d%d%d%d",&l,&r,&d,&t); 93 link(rt[d],1,n,l,r,i+n); add(i+n,T,t); 94 } 95 printf("%d\n",dinic()); 96 return 0; 97 }