RT,现在我的做法是各方面碾了标算,大家来看看到底是算法假加数据水还是这个题本身就可以这么做。
思路:由于始终存在一条 1−>n 的路径,考虑保这条路径。
考虑所有路径按照询问来说最晚不连通的那条,显然我们保证这条不被删即可。
于是按照询问时间戳给边定权,不被询问的边认为无限大(可以认为这些边都在询问的边之后被删掉)。多次询问的边以第一次为准。(显然第二次即之后的询问都是无效的,第一次被删之后就没法删;第一次不被删之后也一定不能被删)
找一条路径,使其经过的边最小边权最大,这条路径就不会被删。
这样可以离线解决本题。下帖代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=0x7f7f7f7f;
const int maxn=2e5;
bool flag[maxn+5];
int fr[maxn+5],to[maxn+5],nex[maxn+5],lk[maxn+5],w[maxn+5],M=0;
int coming[maxn+5];
int ask[maxn+5];
int fst[maxn+5];
bool ans[maxn+5];
struct road{
int v,id,w;
bool operator < (const road &x) const
{
return w<x.w;
}
};
priority_queue<road,vector<road> , less<road> > Q;
void solve(int n)
{
road item,tp;
item.v=1;item.w=INF;item.id=INF;Q.push(item);
for (int i=1;i<=n;i++) flag[i]=false;
while(!Q.empty())
{
tp=Q.top();
Q.pop();
if (flag[tp.v]) continue;
flag[tp.v]=true;
coming[tp.v]=tp.id;
for (int i=lk[tp.v];i>0;i=nex[i])
{
if (!flag[to[i]])
{
item.v=to[i];
item.id=i;
item.w=w[i];
Q.push(item);
}
}
}
int p=n;
while(coming[p]<INF)
{
if (w[coming[p]]<INF)
ans[w[coming[p]]]=true;
p=fr[coming[p]];
}
return ;
}
int main()
{
int n,m,q,u,v;
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=n;i++) lk[i]=-1,coming[i]=INF;
for (int i=1;i<=m;i++) {
scanf("%d%d",&u,&v);
fr[i]=u;to[i]=v;nex[i]=lk[u];lk[u]=i;w[i]=INF;
}
for (int i=1;i<=q;i++)
{
scanf("%d",&ask[i]);
w[ask[i]]=min(w[ask[i]],i);
ans[i]=false;
}
solve(n);
for (int i=1;i<=q;i++)
{
if (ans[i]||i!=w[ask[i]]) puts("0");
else puts("1");
}
return 0;
}
代码应该还是不丑的。大家有时间愿意帮忙的话就来看看有没有问题吧。若有问题给个hack啥的,谢谢大家了。