题解
因为要最小割,自然想到要用最大流
建立每一个时间节点,从 S 向每个时间节点建一条流量为 1,费用为 0 的边。从对于盗贼 i,向 T 建一条流量为 1,费用为 cost(i)的边,从盗贼范围内的时间节点向盗贼建一条流量为 1,费用为 0 的边,然后跑费用流。时间效率 O(n^3),会 TLE。
然后想优化,因为时间节点的连边都是连续的,如果把时间节点离散化,效率自然就提上去了。
可以考虑类似于线段树的方式,将时间节点构造成一棵线段树,子节点向父亲节点连一条流量为 inf,费用为 0 的边。在时间向盗贼连边时就只需要将范围内的区间和盗贼相连就可以了,连的边数就优化到了 log(n)。这样子再跑费用流的效率就优化到 O(n*log^2 n)
代码
#include<bits/stdc++.h>
#define maxn 5002
#define inf 1e9
using namespace std;
struct segtree{int s,l,r;}st[maxn*4];
struct edge{int s,to,next,w,c;}e[20000002];
int ans,n,a[maxn],b[maxn],c[maxn],cnt=1,tot,S,T=1000001,mx,head[1000002],dis[1000002],flag[1000002],fa[1000002];
void add(int s,int t,int w,int c){
e[++cnt].s=s;
e[cnt].to=t;
e[cnt].w=w;
e[cnt].c=c;
e[cnt].next=head[s];
head[s]=cnt;}
void ins(int s,int t,int w,int c){
add(s,t,w,c);
add(t,s,0,-c);}
void ask(int rt,int l,int r,int x){
if(st[rt].l>=l&&st[rt].r<=r){
ins(st[rt].s,x,inf,0);
return;}
int mid=st[rt].l+st[rt].r>>1;
if(mid>=l) ask(rt<<1,l,r,x);
if(mid<r) ask(rt<<1|1,l,r,x);
return;}
void build(int rt,int l,int r){
st[rt].l=l,st[rt].r=r,st[rt].s=++tot;
if(l==r){
ins(S,tot,1,0);
return;}
int mid=(l+r)/2;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
ins(st[rt<<1].s,st[rt].s,inf,0);
ins(st[rt<<1|1].s,st[rt].s,inf,0);
return;}
bool spfa(){
for(int i=0;i<=T;i++) dis[i]=inf;
dis[0]=0;
queue<int> q;
q.push(0);flag[0]=1;
while(!q.empty()){
int now=q.front();q.pop();
for(int k=head[now];k;k=e[k].next){
if(e[k].w && dis[e[k].to]>dis[now]+e[k].c){
fa[e[k].to]=k;
dis[e[k].to]=dis[now]+e[k].c;
if(!flag[e[k].to]){
flag[e[k].to]=1;
q.push(e[k].to);}
}
}flag[now]=0;}
if(dis[T]==inf) return 0;
return 1;}
void mcf(){
int min1=inf;
for(int k=fa[T];k;k=fa[e[k].s]) min1=min(min1,e[k].w);
for(int k=fa[T];k;k=fa[e[k].s]){
ans+=min1*e[k].c;
e[k].w-=min1;
e[k^1].w+=min1;}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]),b[i]--,mx=max(b[i],mx);
build(1,1,mx);
for(int i=1;i<=n;i++){
ask(1,a[i],b[i],++tot);
ins(tot,T,1,-c[i]);}
while(spfa()) mcf();
cout<<-ans<<endl;
}