这道题好暴力啊

发现自己刚学\(OI\)的时候对着这道题写了一个大搜索

发现已经看不懂了

果然我现在菜到连一年半前的我都不如了

这其实是一个基环树\(dp\)啦,基环树上的最大点独立集

其实很简单,我们都知道树上的最大点独立集是可以\(O(n)\)做出来的,而基环树和树之间唯一的一个差距就是基环树多了一条边,于是就会导致失去像树那样优美的结构,并不能简单\(dp\)了

我们必须让树回复到优美的状态,于是我们断开环上的一条边,让基环树变成一棵树之后再跑一遍树上的最大点独立集

但是原来断开的那条边所连接的两个点是不能同时被选择的,所以我们可以分别以这两个个点为根,跑两遍最大点独立集,强制另一个点不能被选择就好了

至于如何找到环上的两个点,我是用了最慢的\(tarjan\)找到了边双,也就是环,并查集和\(dfs\)能做到更优

还有两个坑点

  1. 图可能不连通

  2. 可能有两个人互相仇恨,于是基环树又变成了树,\(tarjan\)没有办法找到环,于是对于这种情况我们得直接跑树上的最大点独立集

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define re register
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 1000005
#define inf 9999999999
struct E
{
int v,nxt;
}e[maxn<<1];
int head[maxn],dfn[maxn],low[maxn];
LL dp[maxn][2];
int st[maxn],a[maxn];
int hate[maxn];
int num,n,m,top,mid,co,cnt;
bool F;
LL ans,tot;
int X,Y;
inline void add_edge(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
void tarjan(int x,int fa)
{
dp[x][0]=dp[x][1]=0;
dfn[x]=low[x]=++cnt;
st[++top]=x;
for(re int i=head[x];i;i=e[i].nxt)
if(!dfn[e[i].v]) tarjan(e[i].v,x),low[x]=min(low[x],low[e[i].v]);
else if(fa!=e[i].v) low[x]=min(low[x],dfn[e[i].v]);
if(low[x]==dfn[x])
{
int sz=0,pre;
do
{
mid=st[top--];
sz++;
if(sz==2)
{
F=1;
X=mid,Y=pre;
}
pre=mid;
}while(x!=mid);
}
}
void dfs(int r,int f,int fa)
{
dp[r][1]=a[r];
for(re int i=head[r];i;i=e[i].nxt)
{
if(e[i].v==fa) continue;
if(X==r&&Y==e[i].v) continue;
if(Y==r&&X==e[i].v) continue;
dfs(e[i].v,f,r);
dp[r][0]+=max(dp[e[i].v][0],dp[e[i].v][1]);
dp[r][1]+=dp[e[i].v][0];
}
if(!f&&r==Y) dp[r][1]=-inf;
if(f&&r==X) dp[r][1]=-inf;
}
void clear(int r,int fa)
{
dp[r][0]=dp[r][1]=0;
for(re int i=head[r];i;i=e[i].nxt)
if(e[i].v!=fa)
{
if(X==r&&Y==e[i].v) continue;
if(Y==r&&X==e[i].v) continue;
clear(e[i].v,r);
}
}
void DFS(int r,int fa)
{
dp[r][1]=a[r];
for(re int i=head[r];i;i=e[i].nxt)
if(fa!=e[i].v)
{
DFS(e[i].v,r);
dp[r][0]+=max(dp[e[i].v][1],dp[e[i].v][0]);
dp[r][1]+=dp[e[i].v][0];
}
}
int main()
{
n=read();
for(re int i=1;i<=n;i++)
{
a[i]=read();
hate[i]=read();
if(hate[hate[i]]==i) continue;
else add_edge(hate[i],i),add_edge(i,hate[i]);
}
for(re int i=1;i<=n;i++)
{
ans=0;
if(dfn[i]) continue;
X=0,Y=0;
tarjan(i,0);
if(!X&&!Y)
{
DFS(i,0);
tot+=max(dp[i][0],dp[i][1]);
continue;
}
dfs(X,0,0);
ans=max(dp[X][0],dp[X][1]);
clear(X,0);
dfs(Y,1,0);
ans=max(max(ans,dp[Y][1]),dp[Y][0]);tot+=ans;
}
std::cout<<tot;
return 0;
}

【[ZJOI2008]骑士】的更多相关文章

  1. BZOJ 1040: [ZJOI2008]骑士 基环加外向树

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1190  Solved: 465[Submit][Status] ...

  2. bzoj 1040: [ZJOI2008]骑士 環套樹DP

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1755  Solved: 690[Submit][Status] ...

  3. bzoj 1040: [ZJOI2008]骑士 树形dp

    题目链接 1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3054  Solved: 1162[Submit][S ...

  4. [ZJOI2008]骑士

    [ZJOI2008]骑士 标签: DP 题目链接 题解 把边看成无向的. 其实就是求这个东西的最大独立集. 但是这不是树,怎么求呢? 其实还是一样的求法. 对于每一个连通块.最多有这个联通块的大小数目 ...

  5. [BZOJ 1040][ZJOI2008]骑士

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5403  Solved: 2060[Submit][Status ...

  6. BZOJ_1040_[ZJOI2008]骑士_树形DP

    BZOJ_1040_[ZJOI2008]骑士_树形DP 题意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪 ...

  7. 洛谷 P2607 [ZJOI2008]骑士 解题报告

    P2607 [ZJOI2008]骑士 题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一 ...

  8. 【洛谷】2607: [ZJOI2008]骑士【树形DP】【基环树】

    P2607 [ZJOI2008]骑士 题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一 ...

  9. 【BZOJ1040】[ZJOI2008]骑士 树形DP

    [BZOJ1040][ZJOI2008]骑士 Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情 ...

  10. [BZOJ1040][ZJOI2008]骑士(环套树dp)

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5816  Solved: 2263[Submit][Status ...

随机推荐

  1. (转)expfilt 命令

    expfilt 命令 原文:https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_72/com.ibm.aix.cmds2/expfilt.ht ...

  2. (转)模块readline解析

    模块readline解析 原文:https://www.cnblogs.com/fireflow/p/4841413.html readline模块定义了一系列函数用来读写Python解释器中历史命令 ...

  3. vuex中filter的使用 && 快速判断一个数是否在一个数组中

    vue中filter的使用 computed: mapState({ items: state => state.items.filter(function (value, index, arr ...

  4. How to add more to Git Bash on Windows

    How to add more to Git Bash on Windows Download the lastest wget binary for windows from https://ete ...

  5. TOJ 1717 WOJ

    描述 Alex likes solving problems on WOJ (http://acm.whu.edu.cn/oak). As we all know, a beautiful ballo ...

  6. 8、列表:ion-list

    1.基本样式 no-lines 属性 隐藏列表项之间的分割符 inset 属性 去掉 ion-list的 外边框. 默认 的 ion-list 是有外边框的.   /* ---示例代码----*/ & ...

  7. mysql四:数据操作

    一.介绍 MySQL数据操作: DML ======================================================== 在MySQL管理软件中,可以通过SQL语句中的 ...

  8. 首页的css

    html,body{ margin:; padding:; background-color: lavenderblush; } a{ color:darkgray; } li{ list-style ...

  9. node的版本控制之nvm的安装与使用

    NVM的安装 windows下的安装: windows下的离线安装: nvm 的windows下载地址:https://github.com/coreybutler/nvm-windows/relea ...

  10. twaver拓扑图拖拽后保存json数据

    功能描述:拓扑图.对节点进行拖拽,序列化获取拓扑图信息,保存到本地localStorage,刷新页面,执行反序列化,从本地获取之前保存的数据,展现之前拖拽后的拓扑 拓展:此处存储用的是web本地存储l ...