BZOJ 3681 线段树合并+网络流

Posted SiriusRen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3681 线段树合并+网络流相关的知识,希望对你有一定的参考价值。

思路:

暴力建图有n*m条边 

考虑怎么优化

(那就只能加个线段树了呗)

然后我就不会写了.....

抄了一波题解

//By SiriusRen
#include <bits/stdc++.h>
using namespace std;
const int N=10050,M=N*100,inf=0x3f3f3f3f;
vector<int>vec[N];
int n,m,first[M],next[M],v[M],w[M],tot,cnt=2,S=1,T=2;
int lson[M],rson[M],root[N],jy,vis[M];
int read(){
    char p=getchar();int x=0;
    while(p<0||p>9)p=getchar();
    while(p>=0&&p<=9)x=x*10+p-0,p=getchar();
    return x;
}
void Add(int x,int y,int z){v[tot]=y,w[tot]=z,next[tot]=first[x],first[x]=tot++;}
void add(int x,int y,int z){Add(x,y,z),Add(y,x,0);}
int insert(int l,int r,int pos,int num){
    pos=++cnt;
    if(l==r){add(cnt,T,1);return pos;}
    int mid=(l+r)>>1;
    if(mid<num)add(pos,rson[pos]=insert(mid+1,r,rson[pos],num),inf);
    else add(pos,lson[pos]=insert(l,mid,lson[pos],num),inf);
    return pos;
}
int merge(int l,int r,int pos,int last){
    if(pos*last==0)return pos+last;
    int now=++cnt,mid=(l+r)>>1;
    if(l==r){add(now,pos,inf),add(now,last,inf);return now;}
    add(now,lson[now]=merge(l,mid,lson[pos],lson[last]),inf);
    add(now,rson[now]=merge(mid+1,r,rson[pos],rson[last]),inf);
    return now;
}
void dfs(int x){
    for(int i=0;i<vec[x].size();i++)
        dfs(vec[x][i]),root[x]=merge(1,n,root[x],root[vec[x][i]]);
}
void query(int l,int r,int pos,int L,int R){
    if(!pos)return;
    if(l>=L&&r<=R){add(cnt,pos,inf);return;}
    int mid=(l+r)>>1;
    if(mid<L)query(mid+1,r,rson[pos],L,R);
    else if(mid>=R)query(l,mid,lson[pos],L,R);
    else query(l,mid,lson[pos],L,R),query(mid+1,r,rson[pos],L,R);
}
bool tell(){
    memset(vis,-1,sizeof(vis));
    queue<int>q;q.push(S),vis[S]=0;
    while(!q.empty()){
        int t=q.front();q.pop();
        for(int i=first[t];~i;i=next[i])
            if(vis[v[i]]==-1&&w[i])vis[v[i]]=vis[t]+1,q.push(v[i]);
    }return ~vis[T];
}
int zeng(int x,int y){
    if(x==T)return y;
    int r=0;
    for(int i=first[x];~i;i=next[i])if(vis[v[i]]==vis[x]+1&&w[i]){
        int t=zeng(v[i],min(w[i],y-r));
        w[i]-=t,w[i^1]+=t,r+=t;
    }if(!r)vis[x]=-1;
    return r;
}
int flow(){int ans=0;while(tell())while(jy=zeng(S,inf))ans+=jy;return ans;}
int main(){
    memset(first,-1,sizeof(first));
    scanf("%d%d",&n,&m);
    for(int i=2;i<=n;i++)vec[read()].push_back(i);
    for(int i=1;i<=n;i++)root[i]=insert(1,n,root[i],read());
    dfs(1);
    for(int i=1;i<=m;i++){
        int l=read(),r=read(),x=read(),y=read();
        cnt++,add(S,cnt,y),query(1,n,root[x],l,r);
    }
    printf("%d\n",flow());
}

 

以上是关于BZOJ 3681 线段树合并+网络流的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3681Arietta 树链剖分+可持久化线段树优化建图+网络流

bzoj3681: Arietta(网络流)

BZOJ3638Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

bzoj3638Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

BZOJ 4756 线段树合并(线段树)

BZOJ.3638.CF172 k-Maximum Subsequence Sum(模拟费用流 线段树)