[APIO2009]抢掠计划

嘟嘟嘟

 

这题读完思路应该马上就有了。

先强连通分量缩点,然后在DAG上dp求最长路即可,并且只在有酒吧的点更新答案。

但是这样不一定正确。原因就是拓扑排序是每一次把入度为0的点加入队列,但对于每一个点的入度,我们重新建图的时候也算上了和起点不连通的点的贡献,导致入度变大,进而导致有些点无法dp到,使答案变小。

所以可以只从起点跑一边tarjan,并且标记能跑到的点。然后重建图的时候特判即可。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("") 
 13 #define space putchar(' ')
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 5e5 + 5;
 21 inline ll read()
 22 {
 23   ll ans = 0;
 24   char ch = getchar(), last = ' ';
 25   while(!isdigit(ch)) last = ch, ch = getchar();
 26   while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
 27   if(last == '-') ans = -ans;
 28   return ans;
 29 }
 30 inline void write(ll x)
 31 {
 32   if(x < 0) x = -x, putchar('-');
 33   if(x >= 10) write(x / 10);
 34   putchar(x % 10 + '0');
 35 }
 36 
 37 int n, m, s, p, a[maxn];
 38 bool bar[maxn];
 39 struct Edge
 40 {
 41   int nxt, to;
 42 }e[maxn];
 43 int head[maxn], ecnt = -1;
 44 void addEdge(int x, int y)
 45 {
 46   e[++ecnt] = (Edge){head[x], y};
 47   head[x] = ecnt;
 48 }
 49 
 50 int dfn[maxn], low[maxn], cnt = 0;
 51 int st[maxn], top = 0;
 52 bool in[maxn], bel[maxn], vis[maxn];
 53 int col[maxn], ccol = 0;
 54 ll val[maxn];
 55 void tarjan(int now)
 56 {
 57   dfn[now] = low[now] = ++cnt;
 58   st[++top] = now; in[now] = 1;
 59   for(int i = head[now], v; i != -1; i = e[i].nxt)
 60     {
 61       v = e[i].to;
 62       if(!dfn[v])
 63     {
 64       tarjan(v);
 65       low[now] = min(low[now], low[v]);
 66     }
 67       else if(in[v]) low[now] = min(low[now], dfn[v]);
 68     }
 69   if(dfn[now] == low[now])
 70     {
 71       int x; ccol++;
 72       do
 73     {
 74       x = st[top--];
 75       in[x] = 0;
 76       col[x] = ccol;
 77       val[ccol] += a[x];
 78       bel[ccol] = 1;
 79       if(bar[x]) vis[ccol] = 1;
 80     }while(x != now);
 81     }
 82 }
 83 
 84 Edge e2[maxn];
 85 int head2[maxn], ecnt2 = -1;
 86 int du[maxn];
 87 void addEdge2(int x, int y)
 88 {
 89   e2[++ecnt2] = (Edge){head2[x], y};
 90   head2[x] = ecnt2;
 91 }
 92 void newGraph(int now)
 93 {
 94   int u = col[now];
 95   if(!bel[u]) return;
 96   for(int i = head[now], v; i != -1; i = e[i].nxt)
 97     {
 98       v = col[e[i].to];
 99       if(u != v && bel[v]) addEdge2(u, v), du[v]++;
100     }
101 }
102 
103 ll dp[maxn], ans = 0;
104 void topo(int s)
105 {
106   queue<int> q; q.push(s);
107   dp[s] = val[s];
108   if(vis[s]) ans = dp[s];
109   while(!q.empty())
110     {
111       int now = q.front(); q.pop();
112       for(int i = head2[now], v; i != -1; i = e2[i].nxt)
113     {
114       v = e2[i].to;
115       dp[v] = max(dp[v], dp[now] + val[v]);
116       if(vis[v]) ans = max(ans, dp[v]);
117       if(--du[v] == 0) q.push(v);
118     }
119     }
120 }
121 
122 int main()
123 {
124   Mem(head, -1);
125   n = read(); m = read();
126   for(int i = 1; i <= m; ++i)
127     {
128       int x = read(), y = read();
129       addEdge(x, y);
130     }
131   for(int i = 1; i <= n; ++i) a[i] = read();
132   s = read(); p = read();
133   for(int i = 1; i <= p; ++i) {int x = read(); bar[x] = 1;}
134   tarjan(s);
135   Mem(head2, -1);
136   for(int i = 1; i <= n; ++i) newGraph(i);
137   topo(col[s]);
138   write(ans), enter;
139   return 0;
140 }
View Code

 

posted @ 2018-11-12 20:01  mrclr  阅读(171)  评论(0编辑  收藏  举报