套路题
把最大子段和\([l,r]\)变成去掉最小的前/后缀。
把前缀\([1,l-1]\)内的数赋权\(1\),\([l,r]\)的赋权\(2\),\([r+1,n]\)赋权\(3\)、
如果一个数\(x\)是正数,则先把\(ans+=x\),如果\(x\)赋权\(1,3\),\(ans-=x\)
否则如果\(x\)赋权\(2\),\(ans-=x\)。
考虑HNOI2013切糕那样子的建图,把每个点拆成\(i,i'\)两个,建立\(n\)条\(3\)个点的链。
如果\(x\)是正数,则\(s->i,i'->t\)连接\(x\)
否则\(i->i'\)连接\(-x\)。
对于题目的每个限制\((x,y)\),如果\(x\)赋权大于\(y\)赋权则不合法。
用HNOI2013切糕的方法连边限制即可。
\(ans-\)最小割就是答案。
#include<bits/stdc++.h>
using namespace std;
#define M 100010
int h[M],nxt[M],v[M],w[M],s,t,dep[M],ec,m,n,ans;
void add(int a,int b,int c){v[++ec]=b;w[ec]=c;nxt[ec]=h[a];h[a]=ec;}
void adj(int a,int b,int c){
add(a,b,c);
add(b,a,0);
}
bool bfs(){
queue<int>q;
q.push(s);
for(int i=1;i<=t;i++)
dep[i]=0;
dep[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=h[x];i;i=nxt[i])
if(w[i]&&!dep[v[i]]){
dep[v[i]]=dep[x]+1;
q.push(v[i]);
if(v[i]==t)
return 1;
}
}
return 0;
}
int dfs(int x,int dis){
if(x==t)
return dis;
int tp=dis;
for(int i=h[x];i;i=nxt[i])
if(dep[v[i]]==dep[x]+1&&w[i]){
int f=dfs(v[i],min(tp,w[i]));
if(!f)
dep[v[i]]=0;
tp-=f;
w[i]-=f;
w[i^1]+=f;
if(!tp)break;
}
return dis-tp;
}
int din(){
int aans=0;
while(bfs()){
int v;
while(v=dfs(s,1e9))
aans+=v;
}
return aans;
}
int main(){
freopen("permutation.in","r",stdin);
freopen("permutation.out","w",stdout);
ec=1;
scanf("%d%d",&n,&m);
t=4*n+1;
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(x>0){
ans+=x;
adj(s,2*i+1,x);
adj(2*i+2,t,x);
}
else
adj(2*i+1,2*i+2,-x);
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
adj(2*x+1,2*y+1,1e9);
adj(2*x+2,2*y+2,1e9);
}
printf("%d",ans-din());
}