码迷,mamicode.com
首页 > 其他好文 > 详细

清北学堂模拟赛d7t6 拯救世界

时间:2017-10-09 22:45:09      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:set   ret   void   scan   eof   pre   amp   多次   span   

技术分享

技术分享

分析:如果题目中没有环的话就是一道裸的最长路的题目,一旦有环每个城市就会被救多次火了。把有向有环图变成有向无环图只需要tarjan一边就可以了.

#include <bits/stdc++.h>

using namespace std;

const int maxn = 500010;
int n,m,head[maxn],nextt[maxn],to[maxn],tot = 1,a[maxn],S,P,p[maxn],v[maxn],vis[maxn];
int scc[maxn],low[maxn],pre[maxn],cnt,dfs_clock,st,head2[maxn],to2[maxn],nextt2[maxn],tot2 = 1;
bool flag[maxn];
long long ans,d[maxn];
stack <int> s;

void add(int x,int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void add2(int x,int y)
{
    to2[tot2] = y;
    nextt2[tot2] = head2[x];
    head2[x] = tot2++;
}

void tarjan(int u)
{
    s.push(u);
    pre[u] = low[u] = ++dfs_clock;
    for (int i = head[u];i;i = nextt[i])
    {
        int v = to[i];
        if (!pre[v])
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else
            if (!scc[v])
            low[u] = min(low[u],pre[v]);
    }
    if (pre[u] == low[u])
    {
        cnt++;
        while (1)
        {
            int t = s.top();
            s.pop();
            v[cnt] += a[t];
            if (t == S)
                st = cnt;
            if (p[t])
                flag[cnt] = 1;
            scc[t] = cnt;
            if (t == u)
                return;
        }
    }
}

void bfs()
{
    queue <int> q;
    q.push(st);
    vis[st] = 1;
    memset(d,-1,sizeof(d));
    d[st] = v[st];
    while (!q.empty())
    {
        int u = q.front();
        vis[u]--;
        q.pop();
        for (int i = head2[u];i;i = nextt2[i])
        {
            int v2 = to2[i];
            if (d[v2] < d[u] + v[v2])
            {
                d[v2] = d[u] + v[v2];
                if (!vis[v2])
                {
                    vis[v2] = 1;
                    q.push(v2);
                }
            }
        }
    }
}

int main()
{
    freopen("save.in","r",stdin);
    freopen("save.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= m; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if (x != y)
        add(x,y);
    }
    for (int i = 1; i <= n; i++)
        scanf("%d",&a[i]);
        scanf("%d%d",&S,&P);
    for (int i = 1; i <= P; i++)
    {
        int t;
        scanf("%d",&t);
        p[t] = 1;
    }
    for (int i = 1; i <= n; i++)
        if (!scc[i])
        tarjan(i);

    for (int i = 1; i <= n; i++)
    {
        for (int j = head[i];j;j = nextt[j])
        {
            int v = to[j];
            if (scc[i] != scc[v])
                add2(scc[i],scc[v]);
        }
    }
    bfs();
    for (int i = 1; i <= cnt; i++)
        if (flag[i])
        ans = max(ans,d[i]);
    cout << ans << endl;

    return 0;
}

 

清北学堂模拟赛d7t6 拯救世界

标签:set   ret   void   scan   eof   pre   amp   多次   span   

原文地址:http://www.cnblogs.com/zbtrs/p/7642910.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!