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 树链剖分+可持久化线段树优化建图+网络流
BZOJ3638Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)