您的位置:首页 > 理论基础 > 计算机网络

【线段树】【树】【网络流】[UOJ#77]A+B Problem

2016-03-19 12:13 691 查看

题目描述





感谢geng给我了正确的数据范围

题目解析

首先我们可以发现如果我们不考虑有奇怪的格子,那么显然我们有ans=∑黑色的格子bi+∑白色的格子wi那么ans=∑i=1nwi+bi−∑i=1nmin{wi,bi}那么我们可以这样跑个网络流求最小割,但是我们这个时候因为多出来了一个pi的限制,那么ans=∑i=1nwi+bi−(∑白色的格子bi+∑黑色的格子wi+∑奇怪的格子pi)我们就对于每一个节点i新建一个节点i′然后连接一条流量为pi的边给他同时我们让(s,i)=bi让(i,t)=wi这样我们的网络流可以分成S和T两个集合当i属于s的时候i显然就是个黑色的了,我们这个时候让i′向所有的k连边INFk满足li≤ak≤ri那么我们分析一下发现因为存在最小割,那么就存在三种情况

i为黑色,此时(s,i)为割边没有流量经过(i,i′)

i为白色,此时(i,i′)为割边那么存在满足条件

i为白色,此时(i,i′)不是割边但是因为存在最小割那么所有满足条件的k均变成了(k,t)满流视作变成了黑色,所以仍然满足条件。

因为n太大,我们要进行优化,我们可以发现对于每一次由i′连接到的k如果按照ai排序均为连续的一个区间,我们可以使用线段树维护,我们这样看作,[l,r]表示为l≤ai≤r中的每一个i提供了一个插头,我们维护的就是一个放满了插头的树,但是因为有先后顺序所以我们用可持久化线段树维护,同时如果我们出现了两个相同的ai怎么办呢,如何让两个i公用一个插头呢,显然将当前的插头连一条INF的边给上一个需要当前位置插头的插头就行了

ans=∑i=1nwi+bi−flow(s,t)

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 5000;
const int MAXLOG = 13;
const int INF = 0x7fffffff;
struct node{
int c,v;
node *next,*back;
}*adj[MAXN*20],edge[1000005],*ecnt=edge;
int n,a[MAXN+10],b[MAXN+10],w[MAXN+10],_l[MAXN+10],_r[MAXN+10],_p[MAXN+10],tmp[MAXN*3+10],m,s,t,ans,sump,dis[MAXN*20],num[MAXN*20], roots[MAXN+10], pcnt;
struct tnode{
int ch[2];
}pool[MAXN*MAXLOG+10];
inline void addedge(int u, int v, int c)
{
++ecnt;
ecnt->v = v;
ecnt->c = c;
ecnt->next = adj[u];
ecnt->back = ecnt+1;
adj[u] = ecnt;
++ecnt;
ecnt->v = u;
ecnt->c = 0;
ecnt->next = adj[v];
ecnt->back = ecnt-1;
adj[v] = ecnt;
}
void Insert(int &x,int y,int l,int r,int i)
{
x=++pcnt;
pool[x]=pool[y];

if(l==r)
{
addedge(x+t,i,INF);

if(y) addedge(x+t,y+t,INF);         //处理相同的a[i]
return;
}
int mid=(l+r)>>1;
if(a[i]>mid) Insert(pool[x].ch[1],pool[y].ch[1],mid+1,r,i);
else Insert(pool[x].ch[0],pool[y].ch[0],l,mid,i);
if(pool[x].ch[1]) addedge(t+x,t+pool[x].ch[1],INF);
if(pool[x].ch[0]) addedge(t+x,t+pool[x].ch[0],INF);
}
void Link(int x,int l,int r,int i)
{
if(l>_r[i]||_l[i]>r)
return;
if(_l[i]<=l&&_r[i]>=r)
{
addedge(n+i,t+x,INF);
return;
}
int mid=(l+r)>>1;
if(pool[x].ch[0]) Link(pool[x].ch[0],l,mid,i);
if(pool[x].ch[1]) Link(pool[x].ch[1],mid+1,r,i);
}
int isap(int u,int augu)
{
if(u==t) return augu;
int augv=0,v,mind=sump-1,delta;
for(node *p=adj[u]; p; p=p->next)
{
v=p->v;
if(p->c)
{
if(dis[u]==dis[v]+1)
{
delta=min(augu-augv,p->c);
delta=isap(v,delta);
augv+=delta;
p->c-=delta;
p->back->c+=delta;
if(augv==augu||dis[s]>=sump)
return augv;
}
mind=min(mind,dis[v]);
}
}
if(!augv)
{
if(!--num[dis[u]])
dis[s]=sump;
dis[u]=mind+1;
num[dis[u]]++;
}
return augv;
}
queue<int> que;
int work()
{
que.push(t);
while(!que.empty())
{
int u = que.front();
que.pop();
for(node *p=adj[u]; p; p=p->next)
{
if(!dis[p->v])
{
dis[p->v] = dis[u] + 1;
que.push(p->v);
}
}
}
dis[t] = 0;
for(int i=1; i<=sump; i++)
{
if(dis[i] == 0)
{
dis[i] = sump;
continue;
}
num[dis[i]]++;
}
num[dis[t]=0]++;
int ret = 0;
while(dis[s] < sump)
ret += isap(s, INF);
return ret;
}
inline void Read(int &u)
{
char ch;
while((ch = getchar()), ch<'0'||ch>'9');
u = ch - '0';
while((ch = getchar()), ch>='0'&&ch<='9') u = u*10+ch-'0';
ungetc(ch, stdin);
}
int main()
{
Read(n);
for(int i=1; i<=n; i++)
{
Read(a[i]);
Read(b[i]);
Read(w[i]);
Read(_l[i]);
Read(_r[i]);
Read(_p[i]);
//scanf("%d%d%d%d%d%d", &a[i], &b[i], &w[i], &_l[i], &_r[i], &_p[i]);
tmp[++m] = a[i];
tmp[++m] = _l[i];
tmp[++m] = _r[i];
ans += w[i] + b[i];
}
sort(tmp+1, tmp+1+m);
m = unique(tmp+1, tmp+1+m) - tmp - 1;
s = 2 * n + 1, t = s + 1;
for(int i=1; i<=n; i++)
{
a[i] = lower_bound(tmp+1, tmp+1+m, a[i]) - tmp;
_l[i] = lower_bound(tmp+1, tmp+1+m, _l[i]) - tmp;
_r[i] = lower_bound(tmp+1, tmp+1+m, _r[i]) - tmp;
addedge(s, i, b[i]);
addedge(i, t, w[i]);
addedge(i, i+n, _p[i]);
}
for(int i=1; i<=n; i++)
{
if(roots[i-1] != 0) Link(roots[i-1], 1, m, i);
Insert(roots[i], roots[i-1], 1, m, i);
}
sump = t + pcnt;
printf("%d\n", ans - work());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息