bzoj1040基环树
。。。
st#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6+;
typedef long long ll;
struct node {
int to,next;
} e[*maxn]; //以这种方式建图,就不需要建树。
int head[maxn]; //可以随意取任何一个节点作为根节点,因为本来就是无向图
int ans = ,cut,root,_root;
int n;
int w[maxn],vis[maxn];
ll dp[maxn][];
//这种建图方式很好
void add(int u,int v) { //无向图,两边都要加
e[ans].to = v; //记录当前第ans根线的to
e[ans].next=head[u]; //指向head[u] 之前指向的那根线。
head[u]=ans++; //指向当前线
}
void dfs(int u,int fa){ //寻找环 ,顺便,标记vis
vis[u] = ;
for(int i=head[u];i!=-;i=e[i].next){
int v = e[i].to;
if(v == fa) continue;
if(!vis[v]) dfs(v,u);
else {root = v;_root=u;cut=i;} //标记要待会作为根节点的root和
} //_root 以及拆掉的线i
} void tree_dp(int u,int fa){
dp[u][] = w[u];
dp[u][] = ;
for(int i=head[u];i!=-;i=e[i].next){
int temp = e[i].to;
if(i == cut || i == (cut^) || temp == fa) continue; //优先级的问题 如果当前线等于拆掉的线return
tree_dp(temp,u);
dp[u][] += dp[temp][];
dp[u][] += max(dp[temp][],dp[temp][]);
}
} int main() {
while(~scanf("%d",&n)) {
ans = ;
memset(w,,sizeof(w));
memset(vis,,sizeof(vis));
memset(dp,,sizeof(dp));
memset(head,-,sizeof(head)); for(int i=; i<=n; i++) {
int u;
scanf("%d %d",&w[i],&u);
add(i,u);
add(u,i);
} ll sum =;
for(int i=;i<=n;i++){
if(vis[i]) continue;
dfs(i,-);
// printf("%d %d %d\n",root,_root,cut);
tree_dp(root,-);//????(将-1改为_root就会wa)
ll temp = dp[root][];
tree_dp(_root,-);///???为什么-1就ac,0就wa
sum+=max(temp,dp[_root][]);
}
printf("%lld\n",sum);
}
return ;
}
wa:
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const int maxn=1e6+;
inline LL max(LL a,LL b){return (a<b?b:a);}
int first[maxn],next[maxn*],to[maxn*];
int edge_count=-;//!!!!重点错误::因为每次两个边是连在一起的所以应该(0,1),(2,3)而不是(1,2),(2,3)【此处指的是边编号】
inline void add(int x,int y){
edge_count++;
to[edge_count]=y;
next[edge_count]=first[x];
first[x]=edge_count;
}
int n,a[maxn];
inline void read(int &a){
a=;int b=;char x=getchar();
while(x<'' || ''<x){
if(x=='-')b=-;
x=getchar();
}
while(''<=x && x<=''){
a=(a<<)+(a<<)+x-'';
x=getchar();
}
a*=b;
}
bool vis[maxn];
int x[maxn],y[maxn],cnt[maxn],p;
void dfs(int root,int fa){ vis[root]=; for(int i=first[root];i!=-;i=next[i]){
if(to[i]==fa)continue;
if(vis [ to[i] ]){
x[p]=root;
y[p]=to[i];
cnt[p]=i;
}
else dfs(to[i],root);
}
}
LL f[maxn][],ans;
//1->选了 0->没选
void search(int root,int fa,int ban){ // printf("%d %d %d\n",root,fa,ban);
f[root][]=(LL)a[root];
f[root][]=0ll; for(int i=first[root];i!=-;i=next[i]){
if(to[i]==fa || i==ban || i==(ban^) )continue;
search(to[i],root,ban);
f[root][]+=f[ to[i] ][];
f[root][]+=max(f[ to[i] ][],f[ to[i] ][]);
} }
int main()
{
//freopen("knight.in","r",stdin);
read(n);
memset(first,-,sizeof(first));
for(int i=,en;i<=n;i++){
read(a[i]);read(en);
add(i,en);
add(en,i);
}
for(int i=;i<=n;i++){
if(!vis[i]){
dfs(i,-);
// printf("%d %d\n",x[p],y[p]);
p++;
}
}
//memset(vis,0,sizeof(vis)); for(int i=;i<p;i++){
LL temp=0ll; //memset(vis,0,sizeof(vis));
search(x[i],0,cnt[i]);
//(之前写的是:search(x[i],y[i],cnt[i]));也是wa
temp=f[ x[i] ][]; // memset(vis,0,sizeof(vis));
search(y[i],0,cnt[i]);
//(只有写成search(y[i],-1,cnt[i]);才能对)
ans+=max(temp,f[ y[i] ][]);
} printf("%lld",ans);
return ;
}
bzoj1040基环树的更多相关文章
- bzoj1040 基环树森林dp
https://www.lydsy.com/JudgeOnline/problem.php?id=1040 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社 ...
- [bzoj1040][ZJOI2008]骑士_树形dp_基环树_并查集
骑士 bzoj-1040 ZJOI-2008 题目大意:n个骑士,每个骑士有权值val和一个讨厌的骑士.如果一个骑士讨厌另一个骑士那么他们将不会一起出战.问出战的骑士最大atk是多少. 注释:$1\l ...
- bzoj1040(ZJOI2008)骑士——基环树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1040 基环树的模板. 套路就是把环断开,先把一端作为根节点,强制不选:再把另一端作为根节点, ...
- 【bzoj1040】[ZJOI2008]骑士 并查集+基环树dp
题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在 ...
- BZOJ1040:骑士(基环树DP)
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境中 ...
- [BZOJ1040][ZJOI2008]骑士 基环树DP
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1040 题目给出了$n$个点和$n$条无向边,即一棵基环树或者基环树森林. 如果题目给的关系 ...
- 基环树DP
基环树DP Page1:问题 啥是基环树?就是在一棵树上增加一条边. Page2:基环树的几种情况 无向 有向:基环外向树,基环内向树. Page3:处理问题的基本方式 1.断环成树 2.分别处理树和 ...
- 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)
1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 908 Solved: 159 [Su ...
- 『Island 基环树直径』
Island(IOI 2008) Description 你准备浏览一个公园,该公园由 N 个岛屿组成,当地管理部门从每个岛屿 i 出发向另外一个岛屿建了一座长度为 L_i 的桥,不过桥是可以双向行走 ...
随机推荐
- Python进阶1---高阶函数、柯里化
高阶函数 不相等 自定义sort函数 内建函数--高阶函数 #sort函数 def sort2(lst,key = None,reverse = False): res = [] if key is ...
- Linux(Ubuntu)使用日记(零)------使用Linux的理由
我为什么要使用Linux呢,也许在某些人看来或许是装B,但是我的原因有点复杂,简单做下总结(以事情的发展历程为顺序) 升级后开机慢关机慢,崩溃.最近刚刚升级了windows,自己原来的win10其实是 ...
- DAY13、迭代器,生成器,枚举
一.迭代器 1.通过迭代器取值的优缺点 优点:不依赖索引取值,完成取值 缺点:不能计算长度,不能指定位取值(只能从前往后逐一取值) 2.可迭代对象 可迭代对象是有—iter—()方法的对象,调用该方法 ...
- mongoDB 文档操作_查
基本查询命令 find 查找复合条件的所有文档 命令 db.collection.find(query,field) 参数 query 查找条件 格式: {ssss:"xxx"}是 ...
- 阶梯Nim问题
问题形式 有\(n\)个位置\(1...n\),每个位置上有\(a_i\)个石子.有两个人轮流操作.操作步骤是:挑选\(1...n\)中任一一个存在石子的位置\(i\),将至少1个石子移动至\(i-1 ...
- google vimium插件的一些简单命令
j: 向下滑动 k: 向上滑动 d: 向下一页 u: 向上一页 x: 关闭页面 r: 刷新页面 gg: 回到顶部 yy: 复制网址 t: 打开新标签 f: 显示页内指令 yt: 复制当前网址并打开 o ...
- [WC2018]通道
题目描述 http://uoj.ac/problem/347 题解 解法1 求三棵树的直径,看起来非常不可做,但是所有边权都是正的,可以让我们想到爬山. 所以我们可以按照BFS求树的直径的方法,随机一 ...
- es上的的Watcher示例
Watcher插件配置(创建预警任务) watcher目前是沒有界面配置的,需要通过Resfulapi调用创建.管理.更新预警任务 创建一个Watcher任务的流程是怎样的? 我们先来看下创建一个预警 ...
- GO语言系列(五)- 结构体和接口
结构体(Struct) Go中struct的特点 1. 用来自定义复杂数据结构 2. struct里面可以包含多个字段(属性) 3. struct类型可以定义方法,注意和函数的区分 4. struct ...
- mycat 使用
介绍 支持SQL92标准 支持MySQL.Oracle.DB2.SQL Server.PostgreSQL等DB的常见SQL语法 遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理. 基 ...