CF1146G Zoning Restrictions 最小割
题意:
你准备在一条街上建房子。这条街上共有nn个地方可以用来建房子,每个房子高度最高为h。若你建了一个高度为aa的房子,那你将得到a^2的收益。但是这条街有mm个分区限制。具体来说,对于第ii个分区限制,若你在l_il 到r_ir 这段区间内最高的房子的高度严格大于了x_ix ,那你将受到c_ic 的罚款。求你的最大收益(房子收益-−罚款)
原题链接:http://codeforces.com/problemset/problem/1146/G
思路:
可以dp,这里讲一个最小割的网络流做法。
首先将每个点的0~h串起来,用h*h-利益
将边转化成损失,每个点建图大致如下。跑出最小割之后h*h*n-maxflow
就是答案了。
graph LR;
id((S)) --inf--> id1((A0))
id1((A0))--h*h-0-->id2((A1))
id2((A1))--h*h-1-->id3((A2))
id3((A2))--h*h-4-->id4((A3))
id4((A3))--h*h-9-->id5((...))
id3((A2))--inf-->id6((lim1))
id6((lim1))--lim1-->id7((T))
id4((A3))--inf-->id8((lim2))
id8((lim2))--lim2-->id7((T))
classDef className fill:#f9f,stroke:#333,stroke-4px,fill-opacity:0.5
class id,id1,id2,id3,id4,id5,id6,id7,id8 className;
linkStyle default fill:#fff,stroke:#f73,stroke-2px,fill-opacity:1.0;
说的不是很清楚,看代码即可。
代码:
#include<bits/stdc++.h>
#define FIO std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll inf=1e9+7;
const int MAXN = 3010;//点数的最大值
const int MAXM = 10010;//边数的最大值
const int INF = 1e9+7;
struct Edge
{
int to,next,cap,flow;
} edge[MAXM]; //注意是 MAXM
int tol;
int head[MAXN];
void init()
{
tol = 2;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0)
{
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
int Q[MAXN];
int dep[MAXN],cur[MAXN],sta[MAXN];
bool bfs(int s,int t,int n)
{
int front = 0,tail = 0;
memset(dep,-1,sizeof(dep[0])*(n+1));
dep[s] = 0;
Q[tail++] = s;
while(front < tail)
{
int u = Q[front++];
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(edge[i].cap > edge[i].flow && dep[v] == -1)
{
dep[v] = dep[u] + 1;
if(v == t)return true;
Q[tail++] = v;
}
}
}
return false;
}
int dinic(int s,int t,int n)
{
int maxflow = 0;
while(bfs(s,t,n))
{
for(int i = 0; i < n; i++)cur[i] = head[i];
int u = s, tail = 0;
while(cur[s] != -1)
{
if(u == t)
{
int tp = INF;
for(int i = tail-1; i >= 0; i--)
tp = min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
maxflow += tp;
for(int i = tail-1; i >= 0; i--)
{
edge[sta[i]].flow += tp;
edge[sta[i]^1].flow -= tp;
if(edge[sta[i]].cap-edge[sta[i]].flow == 0)
tail = i;
}
u = edge[sta[tail]^1].to;
}
else if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to])
{
sta[tail++] = cur[u];
u = edge[cur[u]].to;
}
else
{
while(u != s && cur[u] == -1)
u = edge[sta[--tail]^1].to;
cur[u] = edge[cur[u]].next;
}
}
}
return maxflow;
}
int n,m,h,l,r,x,c;
inline int idx(int x,int y){
return x*(h+1)+(y+1);
}
int main(){
FIO;
int tt;
cin>>n>>h>>m;
int ans=h*h*n;
init();
int s=0,t=n*(h+1)+m+1;
for(int i=0;i<n;i++){
addedge(s,idx(i,0),inf);
for(int j=0;j<h;j++){
addedge(idx(i,j),idx(i,j+1),h*h-j*j);
}
}
for(int i=1;i<=m;i++){
cin>>l>>r>>x>>c;
for(int j=l;j<=r;j++){
if(x<h)addedge(idx(j-1,x+1),n*(h+1)+i,inf);
}
addedge(n*(h+1)+i,t,c);
}
cout<<ans-dinic(s,t,t+1)<<endl;
return 0;
}