• [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
    ",dinic());
    96     return 0;
    97 }
  • 相关阅读:
    下载ORACLE中BLOB内容到客户端
    VIEW_PK
    带下拉框的GridView的OnRowEditing
    HyperLinkField
    ArcEngine开发 退出系统报错
    【转载】Winform 中的控件透明设置要点
    【转载】大整数相乘
    c# oracle 分页
    view_fk
    ITopologicalOperator Intersect
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10818934.html
Copyright © 2020-2023  润新知