【线段树】【树】【网络流】[UOJ#77]A+B Problem
题目描述
感谢geng给我了正确的数据范围
题目解析
首先我们可以发现如果我们不考虑有奇怪的格子,那么显然我们有
i 为黑色,此时(s,i) 为割边没有流量经过(i,i′) i 为白色,此时(i,i′) 为割边那么存在满足条件i 为白色,此时(i,i′) 不是割边但是因为存在最小割那么所有满足条件的k 均变成了(k,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;
}