[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 }

 

posted @ 2019-05-06 12:47  HocRiser  阅读(297)  评论(0编辑  收藏  举报