[拓扑排序][DP][Tarjan][并查集]JZOJ 4253 QYQ在艾泽拉斯

Posted mastervan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[拓扑排序][DP][Tarjan][并查集]JZOJ 4253 QYQ在艾泽拉斯相关的知识,希望对你有一定的参考价值。

Description

在艾泽拉斯的无尽之海里,有着一群不为人知的由各个种族的冒险者统治的岛屿,这些岛屿都很庞大,足以在上面建造许多的城市,城市之间有一些单向道路连接。
有一天,QYQ无意中发现了这些岛屿,并且发现在每个城市的地下都或多或少埋藏着一些装备、金币、宝物……
可是正当QYQ兴奋不已打算全部把它们拿走时,他却惊奇的发现你的魔法在这里被限制住了,唯一可用的技能就是闪现,而且魔法只够他使用K次这个技能了,每次使用这个技能QYQ只能从一个岛屿上闪现到另外一个岛屿上。每一个岛屿只能登上一次,QYQ可以从任何一个城市开始旅程,在任何一个城市结束旅程。
城市的数量共有n个,有m条道路,每一条道路有两个参数u,v,表示从u到v有一条道路,但你只能由u到v走,两个城市属于相同的岛屿当且仅当暂时将所有道路视为双向道路时可以从其中一个城市走到另一个城市(可以途径其它城市)。
每一个城市都有一个宝物的总价值v[i],你的任务是帮助QYQ得到最大总价值的宝物,并输出这个值。
 

Input

从文件azeroth.in中输入数据。
输入的第一行包含两个整数n,m
输入的第二行到第m+1行,每行包含2个整数u,v,代表你可以从城市u走到城市v
输入的第m+2行包含n个整数,第i个整数代表v[i],即这个城市的宝物总价值。
输入的第m+3行包含一个整数K,代表你可以使用技能的次数。

Output

输出到文件azeroth.out中。
输出的第一行包含一个整数,代表QYQ能获得的最大的宝物总价值
 

Sample Input

3 2
1 2
3 1
1 2 1
0

Sample Output

4
样例说明:
QYQ从3号点开始,走到2号点,最后走到1号点,结束旅程,共获得1+2+1=4价值的宝物
 

Data Constraint

对于30%的数据:n<=10,K=0
对于50%的数据:n<=100,m<=100,K<=1
对于100%的数据:1<=n<=100000,1<=m<=1000000,1<=v[i]<=1000,0<=K<=100000
图中可能会有重边、自环。

分析

水题

tarjan缩完点在拓扑序上随便DP,并查集维护连通块

 

技术分享图片
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <queue>
#include <algorithm>
using namespace std;
const int N=1e5+10;
struct Edge {
    int u,v,nx;
}g[10*N];
int cnt,list[N],val[N],w[N],f[N],deg[N],fa[N],ans[N];
int low[N],dfn[N],tme;
int stk[N],top,bel[N],id,stack[N],tp,icnt;
bool instk[N],vis[N];
int n,m,k;

int Get_F(int x) {return fa[x]==x?x:fa[x]=Get_F(fa[x]);}

void Add(int u,int v) {g[++cnt]=(Edge){u,v,list[u]};list[u]=cnt;}

void Tarjan(int v0) {
    stack[++tp]=v0;
    while (tp) {
        int u=stack[tp],i;
        if (!dfn[u]) low[u]=dfn[u]=++tme,stk[++top]=u,instk[u]=1;
        for (i=list[u];i;i=g[i].nx)
            if (!dfn[g[i].v]) break;
            else if (instk[g[i].v]) low[u]=min(low[u],dfn[g[i].v]);
        if (!i&&tp>1) low[stack[tp-1]]=min(low[stack[tp-1]],low[u]);
        if (!i) {
            if (dfn[u]==low[u]) {
                ++id;
                do {
                    bel[stk[top]]=id;instk[stk[top]]=0;w[id]+=val[stk[top]];
                }
                while (stk[top--]!=u);
            }
            tp--;
        }
        else stack[++tp]=g[i].v;
    }
}

bool CMP(int a,int b) {
    return a>b;
}

void ToppoSort() {
    queue<int> q;
    while (!q.empty()) q.pop();
    for (int i=1;i<=id;i++) if (!deg[i]) q.push(i);
    while (!q.empty()) {
        int u=q.front();q.pop();f[u]+=w[u];
        for (int i=list[u];i;i=g[i].nx) {
            f[g[i].v]=max(f[g[i].v],f[u]);deg[g[i].v]--;
            if (!deg[g[i].v]) q.push(g[i].v);
        }
    }
    for (int i=1;i<=id;i++)
        ans[Get_F(i)]=max(ans[Get_F(i)],f[i]),icnt+=!vis[Get_F(i)],vis[Get_F(i)]=1;
    sort(ans+1,ans+n+1,CMP);
    int lans=0;
    for (int i=1;i<=min(k+1,icnt);i++) lans+=ans[i];
    printf("%d
",lans);
}

int main() {
    freopen("azeroth.in","r",stdin);freopen("azeroth.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),Add(u,v);
    for (int i=1;i<=n;i++) scanf("%d",&val[i]);
    scanf("%d",&k);
    for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i);
    cnt=0;memset(list,0,sizeof list);
    for (int i=1;i<=id;i++) fa[i]=i;
    for (int i=1;i<=m;i++)
        if (bel[g[i].u]!=bel[g[i].v])
            deg[bel[g[i].v]]++,fa[Get_F(bel[g[i].u])]=Get_F(bel[g[i].v]),Add(bel[g[i].u],bel[g[i].v]);
    ToppoSort();
}
View Code

 

以上是关于[拓扑排序][DP][Tarjan][并查集]JZOJ 4253 QYQ在艾泽拉斯的主要内容,如果未能解决你的问题,请参考以下文章

noip知识点

HDU1811 拓扑排序判环+并查集

1/31并查集,拓扑排序

HDOJ1811并查集预处理+拓扑排序

Codeforces Round #541 (Div. 2) D 并查集 + 拓扑排序

[HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)