這道題很是吼啊!!php
最小割的解法想想仍是比較容易想到的。ios
最大化價值的方法能夠當作總和減去最小化損失。優化
暴力的解法就是$<S,i,b[i]>$割掉表示選白色,$<i',T,w[i]>$割掉表示選黑色,$<i,i',p[i]>$表示若是$i$和$i'$不一樣則付出代價,$<i',j,INF>$表示和$j$是不會被割的。spa
這樣直接求出$mincut$,而後答案就是$\sum(b[i]+w[i])-mincut$。blog
可是這樣的邊數是$N^{2}$的,最後會被卡,因此要去優化。ip
這類狀況的優化比較明顯的就是影響的範圍是一段區間,因此比較常見的是用線段樹的節點去表示對一個區間的影響,來達到優化的目的,即連$<i',seg[l,r],INF>$。get
首先確定是線段樹中的$<fa,son[0/1],INF>$,這裏葉子節點直接連所對應的點,即$<leaf_{i},i,INF>$。string
對於$1<=j<i$,能夠考慮把普通的線段樹換成可持久化線段樹便可。it
這裏有一個問題就是$a[i]$用同一個葉子節點表示的會出現重複,因此須要新版本的葉子連向老版本的葉子$<new,old,INF>$io
這樣邊數和點數都是$NlogN$的,就能夠經過了。
搞起來有點蛋疼...思路清晰的話不是很難寫。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 100010 #define MAXM 750010 int N,a[MAXN],b[MAXN],w[MAXN],l[MAXN],r[MAXN],p[MAXN],ans; struct EdgeNode{ int next,to,cap; }edge[MAXM<<1]; int head[MAXN],cnt=1; inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;} inline void InsertEdge(int u,int v,int w) {/*printf("<%d %d>\n",u,v);*/ AddEdge(u,v,w); AddEdge(v,u,0);} #define INF 0x7fffffff int h[MAXN],S,T,cur[MAXN]; inline bool bfs() { queue<int>q; for (int i=S; i<=T; i++) h[i]=-1; h[S]=1; q.push(S); while (!q.empty()) { int now=q.front(); q.pop(); for (int i=head[now]; i; i=edge[i].next) if (h[edge[i].to]==-1 && edge[i].cap) h[edge[i].to]=h[now]+1,q.push(edge[i].to); } return h[T]!=-1; } inline int dfs(int loc,int low) { if (loc==T) return low; int used=0,w; for (int i=cur[loc]; i; i=edge[i].next) if (edge[i].cap && h[edge[i].to]==h[loc]+1) { w=dfs(edge[i].to,min(edge[i].cap,low-used)); edge[i].cap-=w; edge[i^1].cap+=w; used+=w; if (used==low) return low; if (edge[i].to) cur[loc]=i; } if (!used) h[loc]=-1; return used; } int Dinic() { int tmp=0; while (bfs()) { for (int i=S; i<=T; i++) cur[i]=head[i]; tmp+=dfs(S,INF); } return tmp; } namespace PrTree{ int sz,lson[MAXM],rson[MAXM],root[MAXN]; inline void Insert(int l,int r,int &x,int y,int pos,int id) { x=++sz; if (l==r) { InsertEdge(2*N+x,id,INF); if (y) InsertEdge(2*N+x,2*N+y,INF); return; } int mid=(l+r)>>1; lson[x]=lson[y]; rson[x]=rson[y]; if (pos<=mid) Insert(l,mid,lson[x],lson[y],pos,id); else Insert(mid+1,r,rson[x],rson[y],pos,id); if (lson[x]) InsertEdge(2*N+x,2*N+lson[x],INF); if (rson[x]) InsertEdge(2*N+x,2*N+rson[x],INF); } inline void Query(int l,int r,int L,int R,int now,int id) { if (!now) return; if (L<=l && R>=r) { InsertEdge(id,2*N+now,INF); return; } int mid=(l+r)>>1; if (L<=mid) Query(l,mid,L,R,lson[now],id); if (R>mid) Query(mid+1,r,L,R,rson[now],id); } }using namespace PrTree; int ls[MAXN],tot; int main() { N=read(); for (int i=1; i<=N; i++) a[i]=read(),b[i]=read(),w[i]=read(),l[i]=read(),r[i]=read(),p[i]=read(),ans+=w[i]+b[i]; for (int i=1; i<=N; i++) ls[++tot]=a[i],ls[++tot]=l[i],ls[++tot]=r[i]; sort(ls+1,ls+tot+1); tot=unique(ls+1,ls+tot+1)-ls-1; for (int i=1; i<=N; i++) a[i]=lower_bound(ls+1,ls+tot+1,a[i])-ls,l[i]=lower_bound(ls+1,ls+tot+1,l[i])-ls,r[i]=lower_bound(ls+1,ls+tot+1,r[i])-ls; S=0; for (int i=1; i<=N; i++) { PrTree::Insert(1,tot,root[i],root[i-1],a[i],i); PrTree::Query(1,tot,l[i],r[i],root[i-1],i+N); } T=2*N+sz+1; for (int i=1; i<=N; i++) InsertEdge(S,i,b[i]),InsertEdge(i,T,w[i]),InsertEdge(i,i+N,p[i]); printf("%d\n",ans-Dinic()); return 0; }