[51nod1325]两棵树的问题

description

题面

solution

点分治+最小割。

点分必选的重心,再在树上dfs判交,转化为最大权闭合子图。

可以做\(k\)棵树的情况。

code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#define RG register
#define il inline
using namespace std;
typedef long long ll;
typedef double dd;
const int N=205;
const int M=20;
const int mod=1e9+7;
const int inf=2147483647;
il ll read(){
    RG ll d=0,w=1;char ch=getchar();
    while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar();
    if(ch==‘-‘)w=-1,ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)d=d*10+ch-48,ch=getchar();
    return d*w;
}

int n,sum,rt,ans=-inf,val[N],ret;
int head[N],nxt[N<<1],to[N<<1],cnt;
il void add(int u,int v){
    to[++cnt]=v;
    nxt[cnt]=head[u];
    head[u]=cnt;
}

int S,T,dhead[N],dnxt[N<<1],dto[N<<1],dval[N<<1],dcnt;
il void addedge(int u,int v,int w){
    dto[++dcnt]=v;
    dnxt[dcnt]=dhead[u];
    dval[dcnt]=w;
    dhead[u]=dcnt;

    dto[++dcnt]=u;
    dnxt[dcnt]=dhead[v];
    dval[dcnt]=0;
    dhead[v]=dcnt;
}

queue<int>Q;int dep[N],cur[N];
il bool bfs(){
    for(RG int i=1;i<=T;i++)dep[i]=0;
    while(!Q.empty())Q.pop();
    dep[S]=1;Q.push(S);
    while(!Q.empty()){
        RG int u=Q.front();Q.pop();
        for(RG int i=dhead[u];i;i=dnxt[i]){
            RG int v=dto[i];
            if(!dep[v]&&dval[i]){
                dep[v]=dep[u]+1;
                Q.push(v);
            }
        }
    }
    return dep[T];
}

int dfs(int u,int t,int power){
    if(u==t)return power;
    for(RG int &i=cur[u];i;i=dnxt[i]){
        RG int v=dto[i];
        if(dep[v]==dep[u]+1&&dval[i]){
            RG int d=0;
            if(d=dfs(v,t,min(power,dval[i]))){
                dval[i]-=d;
                dval[i^1]+=d;
                return d;
            }
        }
    }
    return 0;
}

il int Dinic(){
    RG int ret=0,d;
    while(bfs()){
        for(RG int i=1;i<=T;i++)cur[i]=dhead[i];
        while(d=dfs(S,T,inf))ret+=d;
    }
    return ret;
}

int sz[N],w[N],cover[N],tot,pd[N];bool vis[N];
void dfscover(int u,int fa){
    cover[u]=tot;pd[u]=dhead[u]=0;
    for(RG int i=head[u];i;i=nxt[i]){
        RG int v=to[i];if(v==fa||vis[v])continue;
        dfscover(v,u);
    }
}
void dfspd(int u,int fa){
    RG int x=u>n?u-n:u;pd[x]++;
    for(RG int i=head[u];i;i=nxt[i]){
        RG int v=to[i];if(v==fa)continue;
        RG int y=v>n?v-n:v;
        if(cover[y]==tot)dfspd(v,u);
    }
}

void dfsadd(int u,int fa){
    RG int x=u>n?u-n:u;if(u<=n&&val[u]>0)ret+=val[u];
    if(u<=n&&val[x])
        val[x]>0?addedge(S,x,val[x]):addedge(x,T,-val[x]);
    for(RG int i=head[u];i;i=nxt[i]){
        RG int v=to[i];if(v==fa)continue;
        RG int y=v>n?v-n:v;
        if(cover[y]==tot&&pd[y]==2){
            addedge(y,x,inf);
            dfsadd(v,u);
        }
    }
}
il void calc(int u){
    tot++;dcnt=1;ret=0;
    S=sum+1;T=sum+2;dhead[S]=dhead[T]=0;
    dfscover(u,0);
    dfspd(u,0);dfspd(u+n,0);
    //addedge(S,u,inf);??????
    dfsadd(u,0);dfsadd(u+n,0);
    ans=max(ans,ret-Dinic());
}

void getrt(int u,int fa){
    sz[u]=1;w[u]=0;
    for(RG int i=head[u];i;i=nxt[i]){
        RG int v=to[i];if(v==fa||vis[v])continue;
        getrt(v,u);sz[u]+=sz[v];
        w[u]=max(w[u],sz[v]);
    }
    w[u]=max(w[u],sum-sz[u]);
    if(w[rt]>w[u])rt=u;
}
void solve(int u){
    calc(u);vis[u]=1;
    for(RG int i=head[u];i;i=nxt[i]){
        RG int v=to[i];if(vis[v])continue;
        sum=sz[v];rt=0;
        getrt(v,0);
        solve(rt);
    }
}

int main()
{
    n=read();
    for(RG int i=1;i<=n;i++)val[i]=read();
    for(RG int i=1,u,v;i<n;i++){
        u=read()+1;v=read()+1;add(u,v);add(v,u);
    }
    for(RG int i=1,u,v;i<n;i++){
        u=read()+1;v=read()+1;add(u+n,v+n);add(v+n,u+n);
    }
    w[0]=sum=n;rt=0;
    getrt(1,0);
    solve(rt);
    printf("%d\n",ans);
    return 0;
}

Question

写最小割的时候,如果使用

addedge(S,u,inf);

来强制重心必选

就会\(WA\)在最后一个数据点

如果不写这句话就\(A\)掉了

如果有\(dalao\)知道是为什么的话欢迎在下方的评论给出建议

原文地址:https://www.cnblogs.com/cjfdf/p/9397769.html

时间: 2024-10-05 12:02:16

[51nod1325]两棵树的问题的相关文章

【LeetCode-面试算法经典-Java实现】【100-Same Tree(两棵树是否相同)】

[100-Same Tree(两棵树是否相同)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given two binary trees, write a function to check if they are equal or not. Two binary trees are considered equal if they are structurally identical and the nodes have the same value. 题目大

数据结构 &amp;&amp; ACM :比较两棵树是否相等。

题目: 有如下数据结构: typedef struct TreeNode{ char c; TreeNode *leftChild; TreeNode *rightChild; }; 现在实现函数:int CompTree(TreeNode *tree1, TreeNode *tree2); 比较两棵树是否相等 代码: typedef struct TreeNode{ char c; TreeNode *leftChild; TreeNode *rightChild; }; //两棵树相等的话返

LeetCode&mdash;&mdash;Same Tree(判断两棵树是否相同)

问题: Given two binary trees, write a function to check if they are equal or not. Two binary trees are considered equal if they are structurally identical and the nodes have the same value.   分析: 考虑使用深度优先遍历的方法,同时遍历两棵树,遇到不等的就返回. 代码如下: /** * Definition f

两棵树,你砍哪一棵?

老教授问:“如果你去山上砍树,正好面前有两棵树,一棵粗,另一棵细,你会砍哪一棵?” 问题一出,大家都说:“当然砍那棵粗的了.” 老教授一笑,说:“那棵粗的不过是一棵普通的杨树,而那棵细的却是红松,现在你们会砍哪一棵?” 我们一想,红松比较珍贵,就说:“当然砍红松了,杨树又不值钱!” 老教授带着不变的微笑看着我们,问:“那如果杨树是笔直的,而红松却七歪八扭,你们会砍哪一棵?” 我们觉得有些疑惑,就说:“如果这样的话,还是砍杨树.红松弯弯曲曲的,什么都做不了!” 老教授目光闪烁着,我们猜想他又要加条

element ui改写实现两棵树

使用element ui组件库实现一个table的两棵树的效果 效果如下,左边树自动展开一级,右边树默认显示楼层,然后可以一个个展开 代码如下 <el-table :data="relativeData" :fit="isFit" height="700px" :row-style="showTr" :row-class-name="tableRowClassName" :header-row-cla

用递归方法判断两棵树是否相等

#include<iostream> #include<vector> #include<stack> #include<string> #include<queue> #include<algorithm> #include<numeric> using namespace std; class node{ public: int val; node* left; node* right; node():val(0),l

LeetCode:Same Tree - 判断两颗树是否相等

1.题目名称 Same Tree(判断两棵树是否相等) 2.题目地址 https://leetcode.com/problems/same-tree/ 3.题目内容 英文:Given two binary trees, write a function to check if they are equal or not. Two binary trees are considered equal if they are structurally identical and the nodes h

比较两棵二叉树--(比较两棵二叉树是否相同/判断一棵二叉树是否是另一棵二叉树的子树)

一,问题介绍 本文章讨论两个问题: ①如何判断两棵二叉树的结构是一样的.对应的每个结点都有着相同的值.--即判断两棵二叉树是一样的 ②给定两棵二叉树,如何判断一棵二叉树是另一棵二叉树的子结构 ③给定两棵二叉树,如何判断一棵二叉树是另一棵二叉树的子树 注意,子结点与子树有那么一点点不同. 上面的二叉树B 是二叉树A 的子结构,但是不能说是二叉树A的子树.但是二叉树C 是 二叉树A的子树. 二,问题分析 1,如何判断两棵二叉树的结构是一样的.且对应的每个结点都有着相同的值. 对于①如何判断两棵二叉树

hdu-3015 Disharmony Trees---离散化+两个树状数组

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3015 题目大意: 有一些树,这些树的高度和位置给出.现在高度和位置都按从小到大排序,对应一个新的rank,任意两棵树的值为min(高度的rank) * abs(位置差的绝对值).问所有任意两棵树的值的和是多少. 解题思路: 按照题意离散化,然后对H从大到小排序,这样可以保证前面的树高度都比当前的高(或者相等).在计算的时候就可以使用当前的H. 和POJ-1990类似 1 #include<iost