uoj77a+b problem (主席树优化建图+最小割)

qwq自己yy的建图
感觉自己捞的一

qwq
首先对于每一个位置有两种颜色,分别有不同的收益,所以不难想到是最小割,相当于把位置划分成黑白两个集合。

那么考虑一个朴素的建图
首先对于一个点 i i ,我们 S > i S->i 边权是黑色的收益的绝对值,表示不选黑色要放弃这么多收益。 i > T i->T 边权是白色的收益的绝对值,也是同理。

然后对于那个奇怪的方格,我们对于每一个点 i i ,新建一个点 p p ,然后连接边权是那个 p i p_i ,然后这个点向他之前合法的点连 i n f inf ,表示这个联系不能被割断。

最后我们用总的正的收益和减去最小割就是答案了。

但是这样建图的复杂度是不能接受的
qwq
应该怎么优化呢。

我们发现实际上每一个点就是向他之前所有点中权值在一段区间内部的点连边,这不就是主席树吗?
通过权值线段树来进行区间连边。
需要注意的是,由于主席树是一个前缀的形式,所以我们每次 m o d i f y modify 的时候,到达最底部,也就是当前位置的权值的时候,要把这个位置现在的 r o o t root 和之前的 r o o t root 连起来才行。

然后再连到对应的编号的点上。

像线段树优化建图那样写就 o k ok

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#define pb push_back
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 2e5+1e2;
const int maxm = 2*maxn;
const int inf = 1e9;
struct Node{
	int a,l,r,b,w,p;
};
int point[maxn],nxt[maxm],to[maxm];
int cnt=1,n,m;
Node a[10010];
int val[maxm];
int h[maxn],vis[maxn];
queue<int> q;
int ymh;
int s,tt;
int root[maxn];
struct pp{
	int l,r; 
}; 
pp t[maxn*10];
void addedge(int x,int y,int w)
{
	nxt[++cnt]=point[x];
	val[cnt]=w;
	to[cnt]=y;
	point[x]=cnt;
}
void insert(int x,int y,int w)
{
	addedge(x,y,w);
	addedge(y,x,0);
}
bool bfs(int s)
{
	memset(h,-1,sizeof(h));
	q.push(s);
	h[s]=0;
	while (!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i=point[x];i;i=nxt[i])
		{
			int p = to[i];
			if (h[p]==-1 && val[i]>0)
			{
				h[p]=h[x]+1;
				q.push(p);
			}
		}
	}
	if (h[tt]==-1) return false;
	return true;
}
int dfs(int x,int low)
{
	if (x==tt || low==0) return low;
	int totflow=0;
	for (int i=point[x];i;i=nxt[i])
	{
		 int p = to[i];
		 if (h[p]==h[x]+1 && val[i]>0)
		 {
		 	int tmp = dfs(p,min(low,val[i]));
		 	low-=tmp;
		 	totflow+=tmp;
		 	val[i]-=tmp;
		 	val[i^1]+=tmp;
		 	if (low==0) return totflow;
		  } 
	}
	if (low>0) h[x]=-1;
	return totflow;
}
int dinic()
{
	int ans=0;
	while (bfs(s))
	{
		ans=ans+dfs(s,inf);
	}
	return ans;
}
int tot;
int modify(int pre,int l,int r,int x,int num)
{
	int now = ++tot;
	if (l==r)
	{
		if (pre!=0) insert(now,pre,inf);
		insert(now,num,inf);
		return now;
	} 
	int mid = l+r >> 1;
	if (x<=mid)
	{
	   t[now].r=t[pre].r;
	   t[now].l=modify(t[pre].l,l,mid,x,num);
	}
	else
	{
		t[now].l=t[pre].l;
		t[now].r=modify(t[pre].r,mid+1,r,x,num); 
	}
	insert(now,t[now].l,inf);
	insert(now,t[now].r,inf);
	return now;
}
void query(int root,int l,int r,int x,int y,int p)
{
	if (x<=l && r<=y)
	{
		insert(p,root,inf);
		return;
	}
	int mid = l+r >>1;
	if (x<=mid) query(t[root].l,l,mid,x,y,p);
	if (y>mid) query(t[root].r,mid+1,r,x,y,p);
}
vector<int> v;
int sum;
int main()
{
  n=read();
  s=maxn-3;
  tot=2*n;
  tt=s+1;
  for (int i=1;i<=n;i++)
  {
  	  a[i].a=read();
  	  v.pb(a[i].a);
  	  a[i].b=read();
  	  a[i].w=read();
  	  a[i].l=read();
  	  a[i].r=read();
  	  a[i].p=read();
  }
  v.pb(2*inf);
  sort(v.begin(),v.end());
  int sz = unique(v.begin(),v.end()) - v.begin();
  v.resize(sz);
  ymh=n;
  for (int i=1;i<=n;i++)
  {
  	a[i].a=lower_bound(v.begin(),v.end(),a[i].a)-v.begin()+1;
  	a[i].l=lower_bound(v.begin(),v.end(),a[i].l)-v.begin()+1;
  	a[i].r=upper_bound(v.begin(),v.end(),a[i].r)-v.begin();
    root[i]=modify(root[i-1],1,sz,a[i].a,i);
  	insert(s,i,abs(a[i].b));
  	if (a[i].b>=0) sum+=a[i].b;
	insert(i,tt,abs(a[i].w));
	if (a[i].w>=0) sum+=a[i].w;
	++ymh;
	insert(i,ymh,a[i].p);
	query(root[i-1],1,sz,a[i].l,a[i].r,ymh);
  }
  int uu = dinic();
  cout<<sum-uu;
  return 0;
}

猜你喜欢

转载自blog.csdn.net/y752742355/article/details/87249639
今日推荐