a + b Problem
题解
分块板子题
这道题主要还是建图跑网络流,其实建图的方法还是很常见的。
我们先观察
p
i
p_{i}
pi在什么时候会产生贡献,很明显,如果
a
i
a_{i}
ai在
[
l
i
,
r
i
]
[l_{i},r_{i}]
[li,ri]中有点为白且这个点选的黑,那它就一定会减去
p
i
p_{i}
pi。
换言之,只有全部选黑时它选黑产生的贡献
b
i
b_{i}
bi,否则其贡献就为
b
i
−
p
i
b_{i}-p_{i}
bi−pi。于是我们就想起了 文理分科,我们可以将向每个点从起点与终点分别连一条为
w
i
w_{i}
wi与
b
i
−
p
i
b_{i}-p_{i}
bi−pi流量的边。
对于每个点的组合,向它的每个所属的节点连一条流量为inf的边,再向终点连一条为
p
i
p_{i}
pi的边,表示该组合全选黑时的额外贡献。
根据最大流最小割定理,如果我们跑最大流,可以得到该图的最小割。
由于所有的割边一定时一种合法的宣发,而且得到的就是最小贡献的选法。故与总贡献相减即可得到最大的贡献。
但很明显,这种做法是一定会T的,总的边数可以达到
n
2
n^2
n2,考虑优化。
由于它的组合是向权值在一定范围内的在它前面的数连边,于是我们很容易就想到了分块。听说主席树也可以做,但那样点数会特别多。
我们可以对权值进行分块,对第
i
i
i个点与它前面的点进行组合的时候,先将它前面的点根据权值分块。
如果一个点的权值为
a
j
a_{j}
aj,就将它连向
a
j
a_{j}
aj所处的块所在的虚点,最后再对在
[
l
i
,
r
i
]
[l_{i},r_{i}]
[li,ri]内的块与点添加与该组合间的流量为inf的边。
由于往后一位会增加一个点入块,我们需要将这个块与点连到一个新点,像可持久化一样。可以发现,总的块点数不会超过
n
n
n,总边数大概是
2
n
n
2n\sqrt{n}
2nn左右的样子。
注意,上面的分块需要在去重后再分块,不然直接分块的话边数可能会被卡到
n
2
n^2
n2级别。
但这个时候你将代码交上去你会发现你还是T了,而且只T了一个点,是第4个数据点。
这个时候就需要请出我们的当前弧优化了,加上当前弧优化,直接快了2倍,T的那个点甚至快了20倍。别问笔者是怎么知道的
现在你再把代码交上去就可以过了。
总时间复杂度为
O
(
n
7
2
)
O\left(n^{\frac{7}{2}}\right)
O(n27),虽然看起来过不了但它的确过了,谁都知道网络流的时间复杂度是基本跑不到的嘛。
update:事实上我们的边如果设为
b
−
p
b-p
b−p的话就会产生负边,而负流量严格来说时不合法的,或许能过
D
a
r
k
B
z
o
j
DarkBzoj
DarkBzoj上的测试点,但事实上会在
U
O
J
UOJ
UOJ的
e
x
t
r
a
t
e
s
t
extra\,test
extratest中挂掉,解决办法是在将我们
b
−
p
b-p
b−p与
w
w
w的边权变为
b
b
b与
w
+
p
w+p
w+p,这样就没有负流量了。
源码
分块
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 20005
#define MAXM 1000005
#define reg register
typedef long long LL;
const LL INF=0x7f7f7f7f7f7f;
template<typename _T>
inline void read(_T &x){
_T f=1;x=0;char s=getchar();
while('0'>s||'9'<s){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,head[MAXN],tot,dep[MAXN],S,T,cnt,b[MAXN];
int tott,fk[200],block[MAXN],n1,cur[MAXN];
LL ans;queue<int> q;
struct edge{int to,nxt;LL flow;int op;}e[MAXM];
struct ming{int a,l,r,p;}s[MAXN];
inline void addEdge(const int u,const int v,const LL w){e[++tot]=(edge){v,head[u],w};head[u]=tot;}
inline void addedge(const int u,const int v,const LL w){addEdge(u,v,w);e[tot].op=tot+1;addEdge(v,u,0);e[tot].op=tot-1;}
bool bfs(){
while(!q.empty())q.pop();
for(reg int i=1;i<=cnt;++i)dep[i]=0,cur[i]=head[i];
q.push(S);dep[S]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(reg int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!dep[v]&&e[i].flow>0){
q.push(v);dep[v]=dep[u]+1;
if(v==T)return 1;
}
}
}
return 0;
}
LL dfs(const int u,LL maxf){
if(u==T||!maxf)return maxf;int res=0;
for(int i=cur[u];i;i=e[i].nxt){
cur[u]=i;int v=e[i].to;if(!e[i].flow||dep[v]!=dep[u]+1)continue;
LL f=dfs(v,min(1ll*e[i].flow,maxf));if(!f)continue;
e[i].flow-=f;e[e[i].op].flow+=f;res+=f;maxf-=f;
if(!maxf)break;
}
return res;
}
inline LL dosaka(){
LL res=0;
while(bfs())res+=dfs(S,INF);
return res;
}
signed main(){
read(n);S=3*n+1;cnt=T=3*n+2;
for(reg int i=1;i<=n;++i){
int a,b,w,l,r,p;
read(a);read(b);read(w);read(l);read(r);read(p);
addedge(S,i,w+p);addedge(i,T,b);addedge(i+n,T,p);addedge(i,i+n,INF);
ans+=b+p+w;s[i]=(ming){a,l,r,p};
}
for(reg int i=1;i<=n;++i)b[++tott]=s[i].a;b[++tott]=1e9+1;b[++tott]=0;
sort(b+1,b+tott+1);tott=unique(b+1,b+tott+1)-b-1;n1=tott/70+1;
for(reg int i=1;i<=n;++i)s[i].a=lower_bound(b+1,b+tott+1,s[i].a)-b;
for(reg int i=1;i<=tott;++i)block[i]=(i+n1-1)/n1;
for(reg int i=1;i<=n;++i){
const int l1=lower_bound(b+1,b+tott+1,s[i].l)-b,al=block[l1]+(b[(block[l1]-1)*n1+1]<s[i].l);
const int r1=lower_bound(b+1,b+tott+1,s[i].r)-b,ar=block[r1]-(b[block[r1]*n1]>s[i].r);
for(reg int j=al;j<=ar;++j)if(fk[j])addedge(fk[j],i+n,INF);
for(reg int j=1;j<i;++j){
if(b[s[j].a]<s[i].l||b[s[j].a]>s[i].r)continue;
if(block[s[j].a]<al||block[s[j].a]>ar)addedge(j,i+n,INF);
}
addedge(i,i+2*n,INF);const int id=block[s[i].a];
if(fk[id])addedge(fk[id],i+2*n,INF);fk[id]=i+2*n;
}
ans-=dosaka();printf("%lld\n",ans);
return 0;
}
附上新打的通过主席树维护的代码,竟然只比分块快一倍。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 5005
#define MAXM 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,idx,tot,tott,head[MAXM],cur[MAXM],dep[MAXM],S,T,totd,d[MAXN],root[MAXN],ans;
queue<int>q;
struct node{int lson,rson,id;}tr[MAXM];
struct ming{int a,l,r;LL b,w,p;}p[MAXM];
struct edge{int to,nxt;LL flow;int op;}e[MAXM<<2];
void addEdge(int u,int v,LL f){e[++tott]=(edge){v,head[u],f};head[u]=tott;}
void addedge(int u,int v,LL f){addEdge(u,v,f);e[tott].op=tott+1;addEdge(v,u,0);e[tott].op=tott-1;}
void insert(int &now,int las,int l,int r,int ai,int aw){
if(l>r||l>ai||r<ai)return ;tr[now=++tot]=tr[las];tr[now].id=++idx;
addedge(aw,idx,INF);if(las)addedge(tr[las].id,idx,INF);
if(l==r)return ;int mid=l+r>>1;
if(ai<=mid)insert(tr[now].lson,tr[las].lson,l,mid,ai,aw);
if(ai>mid)insert(tr[now].rson,tr[las].rson,mid+1,r,ai,aw);
}
void modify(int rt,int l,int r,int al,int ar,int aw){
if(l>r||l>ar||r<al||al>ar||!rt)return ;int mid=l+r>>1;
if(al<=l&&r<=ar){addedge(tr[rt].id,aw,INF);return ;}
if(al<=mid)modify(tr[rt].lson,l,mid,al,ar,aw);
if(ar>mid)modify(tr[rt].rson,mid+1,r,al,ar,aw);
}
bool bfs(){
for(int i=1;i<=idx;i++)dep[i]=0,cur[i]=head[i];
while(!q.empty())q.pop();q.push(S);dep[S]=1;
while(!q.empty()){
int u=q.front();q.pop();//printf("while %d %d\n",u,dep[u]);
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(dep[v]||e[i].flow<=0)continue;
//printf("%d link to %d\n",u,v);
q.push(v);dep[v]=dep[u]+1;if(v==T)return 1;
}
}
return 0;
}
LL dfs(int u,LL maxf){
if(u==T||!maxf)return maxf;LL res=0;
for(int i=cur[u];i;i=e[i].nxt){
cur[u]=i;int v=e[i].to;if(!e[i].flow||dep[v]!=dep[u]+1)continue;
LL f=dfs(v,min(e[i].flow,maxf));if(!f)continue;
e[i].flow-=f;e[e[i].op].flow+=f;res+=f;maxf-=f;if(!maxf)break;
}
return res;
}
LL sakura(){LL res=0;while(bfs())res+=dfs(S,INF);return res;}
signed main(){
read(n);idx=n;S=++idx;T=++idx;
for(int i=1;i<=n;i++)
read(p[i].a),read(p[i].b),read(p[i].w),
read(p[i].l),read(p[i].r),read(p[i].p),d[++totd]=p[i].a;
sort(d+1,d+totd+1);totd=unique(d+1,d+totd+1)-d-1;
for(int i=1;i<=n;i++)
ans+=p[i].b+p[i].w+p[i].p,
p[i].a=lower_bound(d+1,d+totd+1,p[i].a)-d,
p[i].l=lower_bound(d+1,d+totd+1,p[i].l)-d,
p[i].r=upper_bound(d+1,d+totd+1,p[i].r)-d-1;
for(int i=1;i<=n;i++){
addedge(S,i,p[i].w+p[i].p);addedge(i,T,p[i].b);
insert(root[i],root[i-1],1,totd,p[i].a,i);
modify(root[i],1,totd,p[i].l,p[i].r,++idx);addedge(idx,T,p[i].p);
if(p[i].l>p[i].a||p[i].r<p[i].a)addedge(i,idx,INF);
}
ans-=sakura();printf("%lld\n",ans);
return 0;
}