网络优化(m个东西能向一段区间服务,每个点服务1的贡献,最多只能服务v次,问最多有多少个点可以被服务到,线段树建边网络流)
题:https://ac.nowcoder.com/acm/problem/20951
题意:m个东西能向一段区间服务,每个点服务1的贡献,最多只能服务v次,问最多有多少个点可以被服务到
分析:朴素地讲可以把某个东西能服务到的区间上的点连接1容量的边,这个东西连接汇点v容量,点连接源点1容量,跑网络流,但是连的边数可能很大;
因为是服务连续区间的点,那么考虑线段树分解,也就是把区间当作点取连接,容量就是边的长度;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<queue> using namespace std; typedef long long ll; #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r #define pb push_back const int inf=0x3f3f3f3f; const ll INF=(1ll<<40); const int M=7e4+4; const int N=2e6+6; int cnt,tot,s,t,n,m; struct node{ int u,v,nextt,w; }e[N]; int head[M],deep[M],cur[M]; int tr[M]; void addedge(int u,int v,int w){ e[tot].v=v; e[tot].w=w; e[tot].nextt=head[u]; head[u]=tot++; e[tot].v=u; e[tot].w=0; e[tot].nextt=head[v]; head[v]=tot++; } bool bfs(){ memset(deep,0,sizeof(deep)); queue<int>que; que.push(s); deep[s]=1; while(!que.empty()){ int u=que.front(); que.pop(); for(int i=head[u];i!=-1;i=e[i].nextt){ int v=e[i].v; if(e[i].w>0&&deep[v]==0){ deep[v]=deep[u]+1; if(v==t) return true; que.push(v); } } } return deep[t]==0?false:true; } int dfs(int u,int fl){ if(u==t) return fl; int x=0,ans=0; for(int i=cur[u];i!=-1;i=e[i].nextt){ int v=e[i].v; if(deep[u]+1==deep[v]&&e[i].w>0){ x=dfs(v,min(fl-ans,e[i].w)); e[i].w-=x; e[i^1].w+=x; if(e[i].w) cur[u]=i; ans+=x; if(ans==fl) return fl; } } if(ans==0) deep[u]=0; return ans; } int dinic(){ int ans=0; while(bfs()){ for(int i=0;i<=t;i++) cur[i]=head[i]; ans+=dfs(s,inf); } return ans; } void init(){ tot=cnt=0; memset(head,-1,sizeof(head)); } void build(int root,int l,int r){ tr[root] = ++cnt; if(l==r){ addedge(0,tr[root],1); return ; } int midd=(l+r)>>1; build(root<<1,l,midd); build(root<<1|1,midd+1,r); addedge(tr[root<<1],tr[root],midd-l+1); addedge(tr[root<<1|1],tr[root],r-midd); } void update(int L,int R,int id,int root,int l,int r){ if(L<=l&&r<=R){ addedge(tr[root],id,r-l+1); return ; } int midd=(l+r)>>1; if(L<=midd) update(L,R,id,root<<1,l,midd); if(R>midd) update(L,R,id,root<<1|1,midd+1,r); } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ init(); build(1,1,n); s=0,t=cnt+m+1; /// cout<<t<<endl; for(int l,r,v,i=1;i<=m;i++){ scanf("%d%d%d",&l,&r,&v); update(l,r,cnt+i,1,1,n); addedge(cnt+i,t,v); } printf("%d\n",dinic()); } return 0; }