根据题意,题目给定的图是一个平面图。如果把
1
1
号点到不了的点和到不了号点的点及所连边删掉,那么图就大概是有一条
1
1
到的链,然后还有一些边覆盖在上面,这样的话它的对偶图就大概是一棵树。
再考虑颜色限制怎么搞,假设
x
x
与其父亲的边在原图中代表边,那么
x
x
在割就表示不选
u+1,...,v−1
u
+
1
,
.
.
.
,
v
−
1
这些点的颜色,于是对于每个颜色建一个点,然后
x
x
向的颜色的点连容量正无穷的双向边。注意到
x
x
在割,那么其子树都在
T
T
割,因此只需要向未被更底层边覆盖的点就可以了。
还有一个细节,注意到一个DAG的对偶图还是一个DAG,且对于任何一条
S
S
到的路径一定存在一条边
(u,v)
(
u
,
v
)
使得
S→u
S
→
u
上的点在
S
S
割,上的点全在
T
T
割(就是不会间隔,这样才对应原图一个合法路径),那么加上颜色限制后可能破坏这一点,所以在本题对偶图中每个点要向其父亲连一条容量为正无穷的边保证这一点。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#define N 1010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,c[N],z[N],S,T,dl[N<<1],ne[N<<1],st[N];
vector<int> gt[N],gr[N],tr[N];
bool bt[N],br[N];
struct node
{
int x,y,w;
}e[N];
struct edge
{
int t,c,f;
edge *next,*rev;
}*con[N<<1];
void ins(int x,int y,int c)
{
edge *p=new edge;p->t=y;p->c=c;p->f=0;p->next=con[x];con[x]=p;
p=new edge;p->t=x;p->c=0;p->f=0;p->next=con[y];con[y]=p;
con[x]->rev=con[y];con[y]->rev=con[x];
}
bool cmp(node p,node q)
{
if(p.y-p.x==q.y-q.x) return p.x<q.x;
return (p.y-p.x<q.y-q.x);
}
bool bfs()
{
memset(ne,0,sizeof(ne));
ne[S]=1;dl[1]=S;bool re=0;
for(int hd=1,tl=1,v=S;hd<=tl;re|=(v==T),v=dl[++hd])
for(edge *p=con[v];p;p=p->next)
if(p->c>p->f&&ne[p->t]==0) ne[p->t]=ne[v]+1,dl[++tl]=p->t;
return re;
}
int dinic(int v,int flow)
{
if(v==T) return flow;
if(ne[v]==-1) return 0;
int re=0;
for(edge *p=con[v];p&&flow;p=p->next)
if(p->c>p->f&&ne[p->t]==ne[v]+1)
{
int o=dinic(p->t,min(flow,p->c-p->f));
p->f+=o;re+=o;
p->rev->f-=o;flow-=o;
}
if(!re) ne[v]==-1;
return re;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{scanf("%d",&c[i]);z[i]=c[i];}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
gt[e[i].x].push_back(e[i].y);
gr[e[i].y].push_back(e[i].x);
}
bt[0]=1;
for(int i=0;i<=n;i++)
if(bt[i])
for(int j=0;j<gt[i].size();j++)
bt[gt[i][j]]=1;
br[n]=1;
for(int i=n;i>=0;i--)
if(br[i])
for(int j=0;j<gr[i].size();j++)
br[gr[i][j]]=1;
if(!bt[n])
{
puts("-1");
return 0;
}
int mm=m;m=0;
for(int i=1;i<=mm;i++)
if(bt[e[i].x]&&bt[e[i].y]&&br[e[i].x]&&br[e[i].y]) e[++m]=e[i];
sort(e+1,e+m+1,cmp);
S=0;T=n+m+1;
for(int i=1;i<=m;i++)
{
int v=S;
for(int j=i+1;j<=m;j++)
if(v||(e[j].x<=e[i].x&&e[j].y>=e[i].y)) {v=j;break;}
tr[v].push_back(i);
}
for(int i=0;i<=m;i++)
for(int j=0;j<tr[i].size();j++)
ins(i,tr[i][j],e[tr[i][j]].w),ins(tr[i][j],i,inf);
for(int i=0;i<=m;i++)
{
int top=0;
for(int j=0;j<tr[i].size();j++)
st[++top]=e[tr[i][j]].x;
sort(st+1,st+top+1);
for(int j=2;j<=top;j++)
ins(i,c[st[j]]+m,inf),ins(c[st[j]]+m,i,inf);
}
for(int i=1;i<=m;i++)
if(!tr[i].size())
{
ins(i,T,inf);
for(int j=e[i].x+1;j<e[i].y;j++)
ins(i,c[j]+m,inf),ins(c[j]+m,i,inf);
}
int ans=0;
while(bfs()) ans+=dinic(S,inf);
if(ans<inf) printf("%d",ans);
else puts("-1");
return 0;
}