[ABC214H]Collecting
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ABC214H]Collecting相关的知识,希望对你有一定的参考价值。
Collecting
题解
网络流板子。
首先题目已经暗示得非常明显了,我们可以考虑按原图的方法将图建出来,跑费用流。
对于原图中的边
(
u
,
v
)
(u,v)
(u,v),我们就连接
o
u
t
u
→
i
n
v
out_{u}\\rightarrow in_{v}
outu→inv,费用为
0
0
0流量为
k
k
k。
而对于点的权值我们就相当于第一次到达这个点,所以在
i
n
u
→
i
n
v
in_{u}\\rightarrow in_{v}
inu→inv上连接费用为
−
v
a
l
u
-val_{u}
−valu,流量为
1
1
1,与费用为
0
0
0流量为
k
k
k的两条边。
但由于可能会产生负环,所以我们要先将原图缩点,得到一个
D
A
G
DAG
DAG,因为很明显,如果我们能够到达一个一个联通块中的某个点,那么我们一定可以到达这个联通块内的其他点,可以将权值都加在一个点上。
但之后仍存在负边,有可能会产生问题,我们考虑将所有路径都变成正的,对于每一条路径都加上
∑
i
=
1
n
v
a
l
i
\\sum_{i=1}^{n}val_{i}
∑i=1nvali。
对于
o
u
t
u
→
i
n
v
out_{u}\\rightarrow in_{v}
outu→inv,我们的边权变为
s
u
m
v
−
1
−
s
u
m
u
sum_{v-1}-sum_{u}
sumv−1−sumu。
i
n
u
→
o
u
t
u
in_{u}\\rightarrow out_{u}
inu→outu的两条边边权变为
0
0
0与
v
a
l
u
val_{u}
valu。
最后在
o
u
t
u
→
t
out_{u}\\rightarrow t
outu→t的边上加上后缀
s
u
m
n
−
s
u
m
u
sum_{n}-sum_{u}
sumn−sumu。
这样保证我们走过整条路径时只有选择了的
v
a
l
val
val没有加上去,最后用
k
⋅
s
u
m
n
k\\cdot sum_{n}
k⋅sumn相减即可得到答案。
时间复杂度
O
(
k
n
l
o
g
n
)
O\\left(knlog\\,n\\right)
O(knlogn),但事实上你必须将连通块的编号反过来才能过,否则会
T
T
T。这太离谱了
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 400005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=1000000000000000000LL;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int lim=400000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-7;
typedef pair<int,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,m,K,tot,head[MAXN],val[MAXN],s,t,pre[MAXN],pw[MAXN];
int dfn[MAXN],low[MAXN],idx,belong[MAXN],cnt,sta[MAXN],stak;
LL dis[MAXN],sum[MAXN],sumval[MAXN];bool insta[MAXN];
vector<int>G[MAXN];
struct edge{int to,nxt;LL paid;int flow,op;}e[MAXN*10];
void addEdge(int u,int v,LL w,int f){e[++tot]=(edge){v,head[u],w,f};head[u]=tot;}
void addedge(int u,int v,LL w,int f){addEdge(u,v,w,f);e[tot].op=tot+1;addEdge(v,u,-w,0);e[tot].op=tot-1;}
struct ming{
LL val;int id;
bool operator < (const ming &rhs)const{return val>rhs.val;}
};
priority_queue<ming>q;
LL sakura(){
LL res=0;
while(1){
for(int i=1;i<=cnt+cnt+2;i++)dis[i]=INF;
while(!q.empty())q.pop();q.push((ming){0,s});dis[s]=0;
while(!q.empty()){
ming tt=q.top();int u=tt.id;q.pop();if(tt.val>dis[u])continue;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;LL w=e[i].paid;
if(dis[v]>dis[u]+w&&e[i].flow>0){
dis[v]=dis[u]+w;pre[v]=u;pw[v]=i;
q.push((ming){dis[v],v});
}
}
}
if(dis[t]>INF-1)break;int minn=10;
for(int i=t;i^s;i=pre[i])minn=min(minn,e[pw[i]].flow);res+=1ll*minn*dis[t];
for(int i=t;i^s;i=pre[i])e[pw[i]].flow-=minn,e[e[pw[i]].op].flow+=minn;
}
return res;
}
void tarjan(int x){
dfn[x]=low[x]=++idx;sta[++stak]=x;insta[x]=1;
int siz=G[x].size();
for(int i=0;i<siz;i++){
int v=G[x][i];
if(!dfn[v])tarjan(v),low[x]=min(low[x],low[v]);
else if(insta[v])low[x]=min(low以上是关于[ABC214H]Collecting的主要内容,如果未能解决你的问题,请参考以下文章
「专题训练」Collecting Bugs(POJ-2096)