【NOIP2016提高A组模拟9.9】爬山

本文介绍了一个基于Tarjan算法解决的最大成就值爬山问题。通过对地图进行有向边标记,利用Tarjan算法进行环压缩,最终通过DFS求得从起点到存档点的最大成就值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//真想把这道题@#@#@##$#@%#*啊!!!!!!!
Description

国家一级爬山运动员h10今天获得了一张有着密密麻麻标记的地图,在好奇心的驱使下,他又踏上了去爬山的路。
对于爬山,h10有一个原则,那就是不走回头路,于是他把地图上的所有边都标记成了有向边。他决定从点S出发,每到达一个新的节点他就可以获得一定的成就值。同时h10又是一个很珍惜时间的运动员,他不希望这次爬山的成就值白白浪费,所以最后他一定要在一个存档点停下,保存自己的成就值。
请你计算出在此次爬山运动中h10能够得到的最大成就值。保证h10能走到存档点。

Input

第一行两个整数 N,M,表示点数和边数。
接下来 M 行,每行两个整数 u,v,表示u到v有一条有向边(没有自环)。
第 M+2 行 N 个正整数,表示每个点的成就值。
接下来一行两个整数 S,p,表示出发点和存档点个数。
下面一行 p 个整数,表示存档点。

Output

一个正整数,表示最大成就值。

Sample Input

5 7
5 1
3 1
2 5
3 5
4 3
4 2
4 5
7 6 3 2 2
4 3
1 5 2

Sample Output

17

Data Constraint

对于 30% 的数据, N,M≤1000,并且地图为有向无环图。
对于 100% 的数据, N,M≤500000。(数据有梯度,注意答案的大小)

比赛时の想法

tarjan缩环后用dfs求出答案,70%

正解

首先,tarjan只要从开始位置开始做一次就可以了,而我一开始把每个没有有向边连向这个点的都tarjan了一遍,超慢哎!
tarjan要用非递归式的,否则会爆栈
tarjan完之后就重新连一下边,然后随便跑个dfs什么的求出答案就可以了
注意开int64哦~~

贴代码

感受终极恐惧吧!!!

var
    a,b:array[0..500005,1..2]of longint;
    h,fen,cc:array[0..500005]of int64;
    h1,h2,h4,cy,dfn,low,t:array[0..500005]of longint;
    bb,bz,bk,h3,pig:array[0..500005]of boolean;
    i,j,k,l,n,m,top,p,s,t1,tc,nod:longint;
procedure qsort(l,r:longint);inline;
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2,1];
    repeat
        while a[i,1]<mid do inc(i);
        while a[j,1]>mid do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then qsort(i,r);
    if l<j then qsort(l,j);
end;
procedure star;inline;
begin
    b[a[1,1],1]:=1;
    for i:=2 to m do
    if a[i,1]<>a[i-1,1] then
    begin
        b[a[i-1,1],2]:=i-1;
        b[a[i,1],1]:=i;
    end;
    b[a[m,1],2]:=m;
end;
procedure tarjan;inline;
var
    i,t,kc,x:longint;
begin
while nod>0 do
begin
    x:=h1[nod];
if h3[x]=false then
begin
    inc(top);
    inc(tc);
    cc[top]:=x;
    dfn[x]:=tc;
    low[x]:=tc;
    bb[x]:=true;
    bz[x]:=true;
end;
    if h4[nod]>b[x,1] then if low[a[h4[nod]-1,2]]<low[x] then low[x]:=low[a[h4[nod]-1,2]];
    for i:=h4[nod] to b[x,2] do
    if i<>0 then
    begin
        if bz[a[i,2]]=false then
        begin
            //tarjan(a[i,2]);
            h4[nod]:=i+1;
            break;

        end else
        if (low[x]>dfn[a[i,2]]) and (bb[a[i,2]]=true) then low[x]:=dfn[a[i,2]];
    end;
    if h4[nod]=i+1 then
    begin
        h3[x]:=true;
        inc(nod);
        h1[nod]:=a[i,2];
        h2[nod]:=nod-1;
        h4[nod]:=b[a[i,2],1];
        continue;
    end;
    if low[x]=dfn[x] then
    begin
        inc(p);
        while cc[top+1]<>x do
        begin
            bb[cc[top]]:=false;
            cy[cc[top]]:=p;
            dec(top);
        end;
    end;
    nod:=h2[nod];
end;
end;
procedure dfs(x:longint);
var
    i:longint;
begin
    for i:=b[x,1] to b[x,2] do
    if (i<>0) and (bz[a[i,2]]=false) then
    begin
        if fen[x]+cc[a[i,2]]>fen[a[i,2]] then
           fen[a[i,2]]:=fen[x]+cc[a[i,2]];
        bz[a[i,2]]:=true;
        dfs(a[i,2]);
        bz[a[i,2]]:=false;
    end;
end;
procedure init;
begin
    assign(input,'t2.in'); reset(input);
    readln(n,m);
    for i:=1 to m do
    begin
        readln(a[i,1],a[i,2]);
        bk[a[i,2]]:=true;
        pig[a[i,1]]:=true;
        pig[a[i,2]]:=true;
    end;
    qsort(1,m);
    star;
    if bk[a[1,1]]=true then
    begin
        bk[a[1,1]]:=false;
        for i:=2 to a[m,1] do if bk[i]=false then bk[a[1,1]]:=true;
    end;
    for i:=1 to n do read(fen[i]);
    readln;
    read(s);
    for i:=1 to a[m,1] do
    if (bz[i]=false) and (bk[i]=false) and (pig[i]=true) then
    begin
        top:=0;
        nod:=1;
        h1[1]:=i;
        h2[1]:=0;
        h4[1]:=b[i,1];
        fillchar(h3,sizeof(h3),false);
        tarjan();
        if bz[s]=true then break;
    end;
    for i:=1 to a[m,1] do
    if (bz[i]=false) and (pig[i]=true) then
    begin
        if bz[s]=true then break;
        top:=0;
        nod:=1;
        h1[1]:=i;
        h2[1]:=0;
        fillchar(h3,sizeof(h3),false);
        tarjan();
    end;
    for i:=1 to m do
    begin
        a[i,1]:=cy[a[i,1]];
        a[i,2]:=cy[a[i,2]];
    end;
    qsort(1,m);
    fillchar(b,sizeof(b),0);
    star;
    fillchar(cc,sizeof(cc),0);
    for i:=1 to n do cc[cy[i]]:=cc[cy[i]]+fen[i];
    readln(t1);
    s:=cy[s];
    fillchar(bb,sizeof(bb),false);
    for i:=1 to t1 do
    begin
        read(t[i]);
        t[i]:=cy[t[i]];
        bb[t[i]]:=true;
    end;
end;
begin
    init;
    fillchar(bz,sizeof(bz),false);
    fillchar(fen,sizeof(fen),0);
    fen[s]:=cc[s];
    bz[s]:=true;
    dfs(s);
    if bb[1]=false then fen[1]:=0;
    for i:=0 to p do
        if (fen[i]>fen[1]) and (bb[i]=true) then fen[1]:=fen[i];
    writeln(fen[1]);
    close(input);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值