题目描述

国家一级爬山运动员h10今天获得了一张有着密密麻麻标记的地图,在好奇心的驱使下,他又踏上了去爬山的路。

对于爬山,h10有一个原则,那就是不走回头路,于是他把地图上的所有边都标记成了有向边。他决定从点S出发,每到达一个新的节点他就可以获得一定的成就值。同时h10又是一个很珍惜时间的运动员,他不希望这次爬山的成就值白白浪费,所以最后他一定要在一个存档点停下,保存自己的成就值。

请你计算出在此次爬山运动中h10能够得到的最大成就值。保证h10能走到存档点。

输入

第一行两个整数 N,M,表示点数和边数。

接下来 M 行,每行两个整数 u,v,表示u到v有一条有向边(没有自环)。

第 M+2 行 N 个正整数,表示每个点的成就值。

接下来一行两个整数 S,p,表示出发点和存档点个数。

下面一行 p 个整数,表示存档点。

输出

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

样例输入

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

样例输出

17

数据范围

对于 30% 的数据, N,M≤1000,并且地图为有向无环图。

对于 100% 的数据, N,M≤500000。(数据有梯度,注意答案的大小)

解法

这道题模型很明显,考虑图是一个DAG(有向无环图)的时候,拓扑排序上动态规划即可。

对于有环的情况,发现一个环的贡献是这个环上所有点的权值之和。

所以使用强连通分量把每个环都缩成一个点。

再使用拓扑排序上动态规划即可。

※手写栈需要

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#define ll long long
#define ln(x,y) ll(log(x)/log(y))
#define sqr(x) ((x)*(x))
using namespace std;
const char* fin="aP2.in";
const char* fout="aP2.out";
const ll inf=0x7fffffff;
const ll maxn=500007,maxm=maxn*2;
ll n,m,i,j,k,st,En,tot,num;
ll a[maxn],fi[maxn],ne[maxm],la[maxm];
ll stack[maxn],dfn[maxn],low[maxn],fa[maxn];
ll ru[maxn];
ll b[maxn];
ll f[maxn],ans;
ll cz[maxn];
bool bz[maxn],en[maxn];
ll read(){
ll x=0;
char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
void add_line(ll a,ll b){
tot++;
ne[tot]=fi[a];
la[tot]=b;
fi[a]=tot;
}
struct handstack{
ll i,j,k,v;
}hs[maxn];
int hst=0;
void handdfs(ll v){
hs[++hst].v=v;
hs[hst].i=0;
while (hst){
if (hs[hst].i){
if (hs[hst].k){
if (!dfn[la[hs[hst].k]]) {
hs[hst+1].v=la[hs[hst].k];
hs[hst+1].i=0;
hst++;
continue;
}else if (bz[la[hs[hst].k]]) low[hs[hst].v]=min(low[la[hs[hst].k]],low[hs[hst].v]);
hs[hst].k=ne[hs[hst].k];
}else{
if (low[hs[hst].v]==dfn[hs[hst].v]){
while (stack[0]>hs[hst].j) {
for (hs[hst].k=fi[stack[stack[0]]];hs[hst].k;hs[hst].k=ne[hs[hst].k]) add_line(hs[hst].v,la[hs[hst].k]);
fa[stack[stack[0]]]=hs[hst].v;
a[fa[stack[stack[0]]]]+=a[stack[stack[0]]];
bz[stack[stack[0]--]]=false;
}
fa[stack[stack[0]]]=hs[hst].v;
bz[stack[stack[0]--]]=false;
}
hst--;
}
}else{
hs[hst].i=1;
dfn[hs[hst].v]=low[hs[hst].v]=++num;
bz[stack[hs[hst].j=++stack[0]]=hs[hst].v]=true;
hs[hst].k=fi[hs[hst].v];
}
}
}
void dfs(ll v){
ll i,j,k;
dfn[v]=low[v]=++num;
bz[stack[j=++stack[0]]=v]=true;
for (k=fi[v];k;k=ne[k])
if (!dfn[la[k]]) {
dfs(la[k]);
low[v]=min(low[la[k]],low[v]);
}else if (bz[la[k]]) low[v]=min(dfn[la[k]],low[v]);
if (low[v]==dfn[v]){
while (stack[0]>j) {
for (k=fi[stack[stack[0]]];k;k=ne[k]) add_line(v,la[k]);
fa[stack[stack[0]]]=v;
a[fa[stack[stack[0]]]]+=a[stack[stack[0]]];
bz[stack[stack[0]--]]=false;
}
fa[stack[stack[0]]]=v;
bz[stack[stack[0]--]]=false;
}
}
void topsort(){
ll i,j,k,head=0,tail=0;
for (i=1;i<=n;i++){
if (fa[i] && i==fa[i]) for (k=fi[i];k;k=ne[k]){
if (/*cz[fa[la[k]]]<i && */fa[la[k]]!=i) ru[fa[la[k]]]++/*,cz[fa[la[k]]]=i*/;
}
}
for (i=1;i<=n;i++) if (!ru[i] && fa[i]==i) {
b[++tail]=i;
f[i]=a[i];
break;
}
while (head++<tail){
if (en[b[head]]) ans=max(ans,f[b[head]]);
for (k=fi[b[head]];k;k=ne[k]) if (fa[la[k]]!=b[head]){
i=fa[la[k]];
f[i]=max(f[i],f[b[head]]+a[i]);
if (--ru[i]==0) b[++tail]=i;
}
}
}
int main(){
n=read();m=read();
for (i=1;i<=m;i++){
j=read();k=read();
add_line(j,k);
}
for (i=1;i<=n;i++) a[i]=read();
st=read();En=read();
handdfs(st);
for (i=1;i<=En;i++) j=read(),en[fa[j]]=true;
topsort();
printf("%lld",ans);
return 0;
}

【JZOJ4771】【NOIP2016提高A组模拟9.9】爬山的更多相关文章

  1. JZOJ 4732. 【NOIP2016提高A组模拟8.23】函数

    4732. [NOIP2016提高A组模拟8.23]函数 (Standard IO) Time Limits: 1500 ms  Memory Limits: 262144 KB  Detailed ...

  2. 【NOIP2016提高A组模拟9.14】数列编辑器

    题目 分析 比赛上,没有注意到询问只询问光标前面,于是只打了个暴力. 因为询问只询问光标前面,首先,当光标向后每移动到一个位置,顺便将这个位置的前缀和,和最大前缀和求出来. 总之,模拟 #includ ...

  3. 【NOIP2016提高A组模拟9.24】总结

    第一题纯模拟,结果那个出题人脑子似乎进水了,空间限制开了1G!!! 导致我捉摸了半天为什么空间要开那么大,最后只能得出上面的结论. 第二题是个矩阵快速幂,比赛上我没把递推式求出来,但是根据各种乱搞,得 ...

  4. 【JZOJ4746】【NOIP2016提高A组模拟9.3】树塔狂想曲

    题目描述 相信大家都在长训班学过树塔问题,题目很简单求最大化一个三角形数塔从上往下走的路径和.走的规则是:(i,j)号点只能走向(i+1,j)或者(i+1,j+1).如下图是一个数塔,映射到该数塔上行 ...

  5. 【JZOJ4745】【NOIP2016提高A组模拟9.3】看电影

    题目描述 听说NOIP2016大家都考得不错,于是CCF奖励省常中了 K 张变形金刚5的电影票奖励OI队的同学去看电影.可是省常中OI队的同学们共有 N(N >= K)人.于是机智的你想到了一个 ...

  6. 【JZOJ4803】【NOIP2016提高A组模拟9.28】求导

    题目描述 输入 输出 样例输入 2x^2+3x+1 样例输出 4x+3 数据范围 样例解释 求导的意思: 多项式是由若干个单项式构成的 单项式的一般形式是ax^b,其中ab都是常数,x是自变量 对于单 ...

  7. 【JZOJ4787】【NOIP2016提高A组模拟9.17】数格子

    题目描述 输入 输出 样例输入 1 10000 3 10000 5 10000 0 0 样例输出 1 11 95 数据范围 每个测试点数据组数不超过10组 解法 状态压缩动态规划. 设f[i][j]表 ...

  8. [jzoj 4668] [NOIP2016提高A组模拟7.19] 腐败 解题报告(质数分类+慢速乘)

    题目链接: http://172.16.0.132/senior/#main/show/4668 题目: 题解: 考虑把A数组里的每个元素分解质因数,对于每个质因数开一个vector存一下包含这个质因 ...

  9. [jzoj 4722] [NOIP2016提高A组模拟8.21] 跳楼机 解题报告 (spfa+同余)

    题目链接: http://172.16.0.132/senior/#main/show/4722 题目: DJL为了避免成为一只咸鱼,来找srwudi学习压代码的技巧.Srwudi的家是一幢h层的摩天 ...

随机推荐

  1. vim 插入行号

    :let i=1000000|g/^/s//\=i.' '/|let i=i+1

  2. C语言作用域、链接属性和存储类型

    C/C++中作用域详解 作用域 编译器可以确认的4种作用域-代码块作用域.文件作用域.函数作用域和原型作用域,一般来说,标识符(包括变量名和函数名)声明的位置决定它的作用域. (1)代码块作用域 一对 ...

  3. Python3.5 安装 & hello world

    1.下载安装python https://www.python.org/downloads/release/python-364/ 2.安装成功运行 python shell 3.或者cmd => ...

  4. main函数执行前后还会发生什么

    问题分析 首先main()函数只不过是提供了一个函数入口,在main()函数中的显示代码执行之前,会由编译器生成_main函数,其中会进行所有全局对象的构造以及初始化工作.简单来说对静态变量.全局变量 ...

  5. utils04_搭建私有Git服务器

    1.远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改.GitHub就是一个免费托管开源代码的远程仓库.但是对于某些视源代码如生命的商业公司来说,既不想公开源代码,又舍不得给G ...

  6. 利用GitHub来进行团队协作开发项目

    首先: 1.项目组长要在GitHub创建一个仓库 2.组长git clone仓库地址到本地   3.组长在本地克隆到的项目里面创建一个Django项目  4.在当前项目下进行git add以及git ...

  7. Luogu P2292 [HNOI2004]L语言(Trie+dp)

    P2292 [HNOI2004]L语言 题面 题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章 \(T\) 是由若干小写字母构成. ...

  8. IDEA工具实现反编译操作

    1.File - Settings... 2.在搜索框中输入“byte” - 勾选 Java Byte code Decompiler选项 点击 OK 键 3.弹出重启IDEA的选择框 选择“rest ...

  9. stream的map用法

    List<String> list = new ArrayList<>();list.add("1");list.add("2");li ...

  10. 一句话介绍python线程、进程和协程

    一.进程: Python的os模块封装了常见的系统调用,其中就包括fork.而fork是linux常用的产生子进程的方法,简言之是一个调用,两个返回. 在python中,以下的两个模块用于进程的使用. ...