传送门
跑最大流的时候加法爆int了,WA了七次。
题意简述:
给一个DAG,记边从
a
i
a_i
ai到
b
i
b_i
bi,边权
c
i
c_i
ci,要从
0
0
0走到
n
n
n,求最短路。
保证
a
i
<
b
i
a_i<b_i
ai<bi,而且不存在
a
i
<
a
j
<
b
i
<
b
j
a_i<a_j<b_i<b_j
ai<aj<bi<bj。
每个点有一个颜色,每种颜色在路径上要么不经过,要么全部经过。
题解:
大概就是有一个DAG,点从0到n标号且排成一排,两条边的区间要么一个包含另一个,要么不交。然后求最短路,每个点有一个颜色,要求每种颜色的点要么全部经过,要么全部不经过。
注意到边的覆盖关系可以表示为一棵树。
由于边没有相交,显然是一个平面图,我们知道平面图最短路等价于期对偶图的最小割。
颜色的奇怪的限制显然不好用最短路,我们用最小割来做。
转对偶图的建图很简单,考虑一下怎么建立出关于颜色的限制。
发现在最小割中显然就是要所有颜色同时属于S集或者T集。
对于每个颜色维护一个集合,集合中的点相互连INF的边,这样就能够保证同时在S集或T集了。
首先划分区间,叶子直接向汇点连INF的边,同时处理一下颜色限制。
否则这条边需要加入左右颜色的集合,然后父亲向它连容量为它的权值的边,然后它向父亲连边INF。
该图的最小割即为答案。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
int S,T=1,tot=1;
cs int N=5e3+7,INF=0x3f3f3f3f;
struct edge{
int to,cap,rev;
edge(int _to,int _cap,int _rev):to(_to),cap(_cap),rev(_rev){}
};
std::vector<edge> G[N];
typedef std::vector<edge>::iterator iter;
iter cur[N];
inline void adde(int u,int v,int uv,int vu=0){
G[u].push_back(edge(v,uv,G[v].size()));
G[v].push_back(edge(u,vu,G[u].size()-1));
}
int lev[N],gap[N];
inline void BFS(){
memset(lev,0,sizeof lev);
memset(gap,0,sizeof gap);
gap[1]=lev[T]=1;std::queue<int> q;q.push(T);
while(!q.empty()){
int u=q.front();q.pop();cur[u]=G[u].begin();
for(edge &e:G[u])if(lev[e.to]==0)++gap[lev[e.to]=lev[u]+1],q.push(e.to);
}
}
bool finished;
inline int dfs(int u,int flow){
if(u==T)return flow;
int ans=0;
for(iter &e=cur[u];e!=G[u].end();++e){
if(e->cap&&lev[e->to]+1==lev[u]){
int delta=dfs(e->to,std::min(flow-ans,e->cap));
if(delta){
e->cap-=delta;
G[e->to][e->rev].cap+=delta;
if((ans+=delta)==flow)return flow;
}
}
}
cur[u]=G[u].begin();
if(!--gap[lev[u]++])finished=true;
++gap[lev[u]];
return ans;
}
inline int Flow(){
int ans=0;
BFS();finished=false;
while(!finished&&ans<INF)ans+=dfs(S,INF);
return ans;
}
class ColorfulPath{
private:
static cs int N=5e3+7;
std::vector<int> G[N],w[N];
std::vector<int> col[N];int c[N];
void build(int l,int r,int fa){
for(int re u=l;u<r;){
int v=0,p=0,m=G[u].size();
if(u!=l)col[c[u]].push_back(fa);
for(int re i=0;i<m;++i)if(G[u][i]>v){
v=G[u][i];
p=i;
}
if(!v){
adde(fa,T,INF);
for(int re i=l+1;i<r;++i)
col[c[i]].push_back(fa);
return ;
}
else {
G[u][p]=0;++tot;
adde(fa,tot,w[u][p],INF);
build(u,v,tot);
u=v;
}
}
}
public:
ColorfulPath(){}
int shortestPath(std::vector<int> a,std::vector<int> b,
std::vector<int> cost,std::vector<int> color){
int n=color.size()+1,m=a.size();
for(int re i=0;i<m;++i){
G[a[i]].push_back(b[i]);
w[a[i]].push_back(cost[i]);
}
for(int re i=1;i<n;++i){
c[i]=color[i-1];
}
build(0,n,S);
for(int re i=1;i<=1000;++i){
int m=col[i].size();
for(int re j=1;j<m;++j)
adde(col[i][j-1],col[i][j],INF,INF);
}
int ans=Flow();
return ans>=INF?-1:ans;
}
};