环套树

bzoj1040 骑士

题目大意:给出每个骑士的攻击力和痛恨的人,每个骑士不能和自己痛恨的人一起出现,选一些骑士使得他们的攻击力最大。

思路:因为每个骑士恨一个人,所以是一个环套树森林(注意n点n边的联通图可能是环套树森林!!!),虽然题目是单向边,但等同于双向边。对于环套树dp的做法,可以搜到环后,把环从一处断开,对于这道题目,对断开后的两点分别为根做树型dp(要求根不能选),加给答案。但是要注意二元环的情况,我们可以对于二元环只加一次无向边(其实是两条有向边),因为二元环完全可以当作有边相连的两点处理,这个时候可能会出现一棵没有环的树,我们需要在退回到dfs起点的那个点的时候人为的做一下dp。

一定要十分注意二元环的情况!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define maxnode 1000005
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},tot=0,x=0,y=0,ai[maxnode]={0};
LL val[maxnode]={0},f[maxnode][2]={0},ans=0;
bool visit[maxnode]={false},ff;
void add(int u,int v)
{
    ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
    ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
}
void dp(int u,int fa)
{
    int i,j;
    f[u][1]=val[u];visit[u]=true;
    for (i=point[u];i;i=next[i])
    {
        if (en[i]!=fa)
        {
            if ((u==y&&en[i]==x)||(u==x&&en[i]==y)) continue;
            dp(en[i],u);
            f[u][0]+=max(f[en[i]][0],f[en[i]][1]);
            f[u][1]+=f[en[i]][0];
        }
    }
}
void dfs(int u,int fa)
{
    int i,j;LL ci=0;
    visit[u]=true;
    for (i=point[u];i;i=next[i])
    {
        if (en[i]!=fa)
        {
            if (visit[en[i]])
            {
                x=u;y=en[i];
                memset(f,0,sizeof(f));
                dp(x,y);ci=max(ci,f[x][0]);
                memset(f,0,sizeof(f));
                swap(x,y);dp(x,y);ci=max(ci,f[x][0]);
                ans+=ci;ff=true;return;
            }
            else
            {
               dfs(en[i],u);if (ff) return;
            }
        }
    }
    if (fa==0)
    {
        x=y=0;dp(u,0);
        ans+=max(f[u][0],f[u][1]);
    }
}
int main()
{
    int n,i,j;
    scanf("%d",&n);
    for (i=1;i<=n;++i) scanf("%I64d%d",&val[i],&ai[i]);
    for (i=1;i<=n;++i)
        if (ai[ai[i]]!=i||ai[i]>i) add(i,ai[i]);
    for (i=1;i<=n;++i)
      if (!visit[i]){ff=false;dfs(i,0);}
    printf("%I64d\n",ans);
}

时间: 2024-12-24 11:12:01

环套树的相关文章

BZOJ 1040: [ZJOI2008]骑士 [DP 环套树]

传送门 题意:环套树的最大权独立集 一开始想处理出外向树树形$DP$然后找到环再做个环形$DP$ 然后看了看别人的题解其实只要断开环做两遍树形$DP$就行了...有道理! 然后洛谷时限再次不科学,卡常失败$SAD$ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; co

BZOJ 1791 岛屿(环套树+单调队列DP)

题目实际上是求环套树森林中每个环套树的直径. 对于环套树的直径,可以先找到这个环套树上面的环.然后把环上的每一点都到达的外向树上的最远距离作为这个点的权值. 那么直径一定就是从环上的某个点开始,某个点结束的. 把环拆成链,定义dp[i]表示第i个点为结束点的最远距离,显然有dp[i]=val[j]+sum[i]-sum[j-1]+val[i].显然可以用单调队列优化这个DP. 剩下的就是这样依次统计每个环套树的直径之和. 对于环套树上找环可以借鉴最小树形图找环的技巧. 首先将边定向,保证每个点的

【BZOJ-3648】寝室管理 环套树 + 树状数组 + 点分治

3648: 寝室管理 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 239  Solved: 106[Submit][Status][Discuss] Description T64有一个好朋友,叫T128.T128是寄宿生,并且最近被老师叫过去当宿管了.宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T64帮忙解决.  T128的寝室条件不是很好,所以没有很多钱来装修.礼间寝室仅由n-1条双向道路连接,而且任意两间寝室之间都可以互

BZOJ 1040 骑士(环套树DP)

如果m=n-1,显然这就是一个经典的树形dp. 现在是m=n,这是一个环套树森林,破掉这个环后,就成了一个树,那么这条破开的边连接的两个顶点不能同时选择.我们可以对这两个点进行两次树形DP根不选的情况. 那么答案就是每个森林的max()之和. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # in

BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4883 [题目大意] 在一个n*m的棋盘上要放置若干个守卫. 对于n行来说,每行必须恰好放置一个横向守卫:同理对于m列来说, 每列必须恰好放置一个纵向守卫.每个位置放置守卫的代价是不一样的, 且每个位置最多只能放置一个守卫,一个守卫不能同时兼顾行列的防御. 请计算控制整个棋盘的最小代价. [题解] 我们将每行和每列看成一个点,用每个格子上的点的权值作为边, 这就构成了一个n+m个点的图

bzoj3648: 寝室管理(环套树+点分治)

好题..写了两个半小时hh,省选的时候要一个半小时内调出这种题目还真是难= = 题目大意是给一棵树或环套树,求点距大于等于K的点对数 这里的树状数组做了一点变换.不是向上更新和向下求和,而是反过来,所以求和的时候sum(k)实际上是求k到n的和 所以我们要求大于等于k的dis的次数和,就是求sum(1,k-1),注意k要减一 如果是树,就是常规的点分治,然后用树状数组维护dis[t]出现的次数 如果是环套树,找环之后割掉一条边,然后先求这棵树的答案.接着考虑过了这条割掉的边s--t的情况:我们以

HDU 6251 Inkopolis(2017 CCPC-Final,I题,环套树 + 结论)

题目链接 HDU 6251 题意 给出一个N个点N条边的无向图.然后给出M个操作,每个操作为(x, y, z),表示把连接 x和y的边的颜色改成z. 求这张无向图中所有边的颜色的连通块数量. 首先不难得到这是一个环套树的结构. 首先考虑一棵树的情形. 设f[i]为i这个结点的所有边中的不同颜色数目. 那么整棵树的所有边的颜色的连通块数量即为$∑f(i) - (n - 1)$ 现在把这个结论推广到环套树上. 设f[i]为i这个结点的所有边中的不同颜色数目. 那么整个图的所有边的颜色的连通块数量即为

【BZOJ】1040: [ZJOI2008]骑士 环套树DP

[题意]给定n个人的ai和bi,表示第i个人能力值为ai且不能和bi同时选择,求能力值和最大的选择方案.n<=10^6. [算法]环套树DP(基环树) [题解]n个点n条边--基环森林(若干环套树子图). 若原图是树,经典DP做法:f[i][0/1]表示i点选或不选的最大能力值和,则f[i][0]=Σmax{f[j][0],f[j][1]},f[i][1]=Σf[j][0]+a[i],j=son[i]. 找环:dfs到访问过的点,标记环上的一条边. 破环:和普通树上DP唯一的区别是,标记边两端不

TopCoder SRM 682 Div1 Problem 450 SuccessfulMerger (环套树 + 分类讨论)

题意  给定一个$n$个点$n$条边的无向图,现在要把这个图进行若干次操作,并选择一个点作为首都. 要求除首都外的任意两个点$u$, $v$,从$u$走到$v$必须经过这个首都. 操作为合并两个相邻的点为一个点,即把这两个点从原图中删除,连接这两个点的边接到新的点上去. 考虑最后这个图的形态其实是一个菊花图,那么可以考虑到最后剩下的这些点其实只有选出的首都和 原图中度数为$1$的点. 但是有这么一种比较特殊的情况. 这个图也是符合题意的. 原来的图其实是一个环套树(环的大小可能为$2$) 如果这