题目本质:只有能做到一路过关斩将的勇者才能冒泡过来救出女主。

主要代码:

 1 const int maxn = 5e5 + 5;
 2 int n, m, a[maxn], ans;
 3 vector<int> edge[maxn];
 4 set<int> can;
 5 
 6 int main() {
 7     read(n), read(m);
 8     rep(i, 1, n) {
 9         read(a[i]);
10     }
11     rep(i, 1, m) {
12         int u, v;
13         read(u), read(v);
14         edge[v].push_back(u);
15         if (v == a[n]) {
16             can.insert(u);
17         }
18     }
19     irep(i, n - 1, 1) {
20         int x = a[i];
21         if (can.find(x) != can.end())    ans++;//这个人被换到了主角后面,钉子户依旧是那些人,筛选标准不变
22         else {//要替换can了
23             set<int> tmp;
24             for (int j : edge[x]) {
25                 if (can.find(j) != can.end())//既能和当前这个钉子户换位又能和主角换位又能和这之前所有钉子户换位的人才能入选
26                     tmp.insert(j);
27             }
28             can = tmp;
29         }
30         if (!can.size())    break;
31     }
32     writeln(ans);
33     return 0;
34 }

 

代码解释:一开始输入完就形成一个勇者集合,然而并不是谁都可以坚挺到最后的。从后向前贪心枚举每个人,这个人要是在勇者集合里,说明他一路挺过来了,ok你把女主冒泡上来以后就可以休息了,就ans++;否则视为阻挠之一(因为别人还得能跟他换位才能继续前行)作为标准更新(筛选)勇者集合。