1. 程式人生 > >[BZOJ3218]a + b Problem-[主席樹+網絡流-最小割]

[BZOJ3218]a + b Problem-[主席樹+網絡流-最小割]

desc online lower n) while for des 思路 string

Description

傳送門

Solution

此處我們按最小割的思路考慮。

暴力:S->i表示該點選黑色的權值b[i];i->T表示該點選白色的權值w[i]。考慮如果某個點i受點j為白點的影響,則將點i連向點j,邊權為p[i]。但這麽做假如有多個點j,p[i]就會被算多次。可以將i點拆為i和i‘。則將i‘連向j,邊權為inf(即該邊不能割),將i連向i‘,邊權為p[i]。

不過這麽搞肯定要爆。考慮一下怎麽優化。

我們發現最耗空間的是i‘->j的邊。(如果l[i],r[i]給的範圍大的話空間簡直。。em)。然後由於是點->區間,考慮線段樹一類的知識點。顯然主席樹是可以的。

主席樹下標按照a的大小。

我們從左到右把點i加進去(a[i],l[i],r[i]要離散化),在主席樹裏找區間[l[i],r[i]]直接連邊;然後將i點連向主席樹內所有(存儲區間包含a[i]的)節點。因為可能在主席樹的某個節點下掛了一堆的點(即很多點i的a[i]相等),我們將主席樹新建的節點向之前的節點連邊。

由於各個點i已經向所有包含它們的主席樹節點連邊,主席樹的節點間無需再連邊了。

主席樹相關的各種邊邊權都為inf。

然後就ok啦啦啦。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include
<algorithm> #include<cmath> #include<queue> using namespace std; const int inf=1e9; int n,m,k; int h[500010],tot; struct pas{int x,y,nxt,w,op,cost;}g[1000100]; int dep[500020],S,T; queue<int>q; struct DINIC{ bool bfs() { int x; memset(dep,0,sizeof(dep));dep[S]=1; while (!q.empty()) q.pop(); q.push(S);
while (!q.empty()) { x=q.front();q.pop(); for (int i=h[x];i;i=g[i].nxt) if (!dep[g[i].y]&&g[i].w) { dep[g[i].y]=dep[x]+1; q.push(g[i].y); if (g[i].y==T) return 1; } } return 0; } int dfs(int x,int flow) { if (x==T||(!flow))return flow; int temp=0,js; for (int i=h[x];i;i=g[i].nxt) if (dep[g[i].y]==dep[x]+1&&g[i].w) { js=dfs(g[i].y,min(flow,g[i].w)); if (js) { g[i].w-=js; g[g[i].op].w+=js; temp+=js; flow-=js; if (!flow) return temp; } } if (!temp) dep[x]=0; return temp; } int dinic() { int ans=0; while (bfs()) ans+=dfs(S,inf); return ans; } }D; void add(int x,int y,int w) { g[++tot].x=x;g[tot].y=y;g[tot].w=w;g[tot].nxt=h[x];g[tot].op=tot+1;h[x]=tot; g[++tot].x=y;g[tot].y=x;g[tot].w=0;g[tot].nxt=h[y];g[tot].op=tot-1;h[y]=tot; } int a[5010],b[5010],w[5010],l[5010],r[5010],p[5010],hehe[5010]; int lc[500010],rc[500010],cnt,rt; void query(int k,int l,int r,int askx,int asky,int p) { if (!k) return; if (askx<=l&&r<=asky) { add(p,k,inf); return; } int mid=(l+r)/2;if (askx<=mid) query(lc[k],l,mid,askx,asky,p); if (asky>mid) query(rc[k],mid+1,r,askx,asky,p); } int modify(int k,int l,int r,int id,int x) { int o=++cnt;lc[o]=lc[k];rc[o]=rc[k]; if (k) add(o,k,inf); add(o,x,inf); if (l==r) return o; int mid=(l+r)/2; if (id<=mid) lc[o]=modify(lc[o],l,mid,id,x);else rc[o]=modify(rc[o],mid+1,r,id,x); return o; } int sum=0; int main() { scanf("%d",&n);cnt=2*n+1; S=0;T=2*n+1; for (int i=1;i<=n;i++) { scanf("%d%d%d%d%d%d",&a[i],&b[i],&w[i],&l[i],&r[i],&p[i]); sum+=w[i]+b[i]; hehe[i]=a[i]; add(S,i,b[i]);add(i,T,w[i]);add(i,n+i,p[i]); } sort(hehe+1,hehe+n+1); for (int i=1;i<=n;i++) { a[i]=lower_bound(hehe+1,hehe+n+1,a[i])-hehe; l[i]=lower_bound(hehe+1,hehe+n+1,l[i])-hehe; r[i]=upper_bound(hehe+1,hehe+n+1,r[i])-hehe-1; if (l[i]<=r[i]) query(rt,1,n,l[i],r[i],n+i); rt=modify(rt,1,n,a[i],i); } cout<<sum-D.dinic(); }

[BZOJ3218]a + b Problem-[主席樹+網絡流-最小割]