Split The Tree

Split The Tree

时间限制: 1 Sec  内存限制: 128 MB

题目描述

You are given a tree with n vertices, numbered from 1 to n. ith vertex has a value wi
We define the weight of a tree as the number of different vertex value in the tree.
If we delete one edge in the tree, the tree will split into two trees. The score is the sum of these two trees’ weights.
We want the know the maximal score we can get if we delete the edge optimally.

输入

Input is given from Standard Input in the following format:
n
p2 p3  . . . pn
w1 w2  . . . wn
Constraints
2 ≤ n ≤ 100000 ,1 ≤ pi < i
1 ≤ wi ≤ 100000(1 ≤ i ≤ n), and they are integers
pi means there is a edge between pi and i

输出

Print one number denotes the maximal score.

样例输入

3
1 1
1 2 2

样例输出

3

来源/分类

2018东北四省赛



题意:每颗树的重量定义为这颗树上所有节点权值不同的个数,现在要割掉一条边,求生成的两颗树最大的重量和。

做法:dfs序,然后枚举每一条边,删除这条边就相当于在dfs序中取走了一个区间,问题就变成了求区间不同数的个数。取走一个区间后,剩下的两块区间求不同数个数可以通过把区间加长一倍来做。

#include<bits/stdc++.h>
#define N 100050
using namespace std;

vector<int>edge[N];
int w[N];
int children[N]={0},number[N]={0},dfsorder[N],len=0;

int dfs(int x)
{
    dfsorder[++len]=x;
    number[x]=len;
    children[x]=1;

    int Size=edge[x].size();
    for(int i=0;i<Size;i++)
    if(number[edge[x][i]]==0)
    {
        children[x]+=dfs(edge[x][i]);
    }
    return children[x];
}

struct ss
{
    int l,r,index,ans;

    bool operator < (const ss& s) const
    {
        return r<s.r;
    }
};
vector<ss>interval;

int c[2*N+5]={0};
void updata(int x,int v)
{
    for(int i=x;i<2*N;i+=i&(-i))c[i]+=v;
}

int Sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=c[x];
        x-=x&(-x);
    }
    return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        int p;
        scanf("%d",&p);
        edge[i].push_back(p);
        edge[p].push_back(i);
    }

    for(int i=1;i<=n;i++)scanf("%d",&w[i]);

    dfs(1);

    for(int i=1;i<=n;i++)
    {
       interval.push_back((ss){number[i],number[i]+children[i]-1,i,0});
       interval.push_back((ss){number[i]+children[i],n+number[i]-1,i,0});
    }
    for(int i=1;i<=n;i++)
    {
        dfsorder[i]=w[dfsorder[i]];
        dfsorder[n+i]=dfsorder[i];
    }
    sort(interval.begin(),interval.end());

    int last[N]={0};
    int c1=1;

    for(int i=0;i<2*n;i++)
    {
        if(interval[i].l>interval[i].r)continue;

        for(int j=c1;j<=interval[i].r;j++)
        {
            if(last[dfsorder[j]]==0)
            {
                updata(j,1);
                last[dfsorder[j]]=j;
            }
            else
            {
                updata(last[dfsorder[j]],-1);
                updata(j,1);
                last[dfsorder[j]]=j;
            }
        }
        interval[i].ans=Sum(interval[i].r)-Sum(interval[i].l-1);
        c1=interval[i].r+1;
    }

    int sum[N]={0},ans=0;

    for(int i=0;i<2*n;i++)
    {
        sum[interval[i].index]+=interval[i].ans;
        ans=max(ans,sum[interval[i].index]);
    }

    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/tian-luo/p/9594262.html

时间: 2024-11-08 20:59:06

Split The Tree的相关文章

Codeforces 1059E. Split the Tree

题目:http://codeforces.com/problemset/problem/1059/E 用倍增可以在nlog内求出每个节点占用一个sequence 时最远可以向父节点延伸到的节点,对每个节点作为sequence 的最后一个元素向上延伸时,将节点的父节点属性合并(类似于并查集的操作), 存在优先队列里保证每次先操作dep最大的节点 #include<iostream> #include<cstdio> #include<cmath> #include<

CF 1039D You Are Given a Tree &amp;&amp; CF1059E Split the Tree 的贪心解法

1039D 题意: 给你一棵树,要求对给定链长于 k = 1, 2, 3, ..., n,求出最大的链剖分. 1059E 题意: 给你一棵带权树,要求对于一组给定的 L, W 求出最小完全竖链剖分满足每条链点数不超过 L,权值和不超过 W. 显然两题是有共同点的,就是让我们求满足一定条件的树的最值链剖分. 比较暴力的可以尝试用 DP 计数,但是我不想深入 DP,因为方程比较复杂,思考起来不太容易. 很巧的是,这两题可以用相似的贪心思想来做. 在思考具体细节之前,需要明确贪心的主要思想:在从下往上

codeforce 1059E Split the Tree

题目http://codeforces.com/problemset/problem/1059/E 参考http://www.cnblogs.com/waldenlake/p/9750249.html 我也想到了贪心,从一个子叶a出发向上每一个都标记直至不满足条件,但其实一个点是可以被重复标记的visit是可以被覆盖的,总是下意识!visit,如果另一个子叶b向上爬得更远的话,经过a和b的父亲之后还能继续向地上爬,这总是能满足最优解. 原文地址:https://www.cnblogs.com/L

Solution: 题解 CF1059E Split the Tree

给出一个堆贪心解法 记点\(u\)的深度为\(d_u(d_1=0)\),父亲为\(f_u\),拥有儿子数量\(es_u\). 首先找到每个点的最远延伸点(点\(u\)的最远延伸点记为\(v_u\)),借助树上倍增即可. 接下来是贪心方法 在每次链连接完后删掉这些点,那么每条链的尾端一定是一个叶子. 那么就想办法找出目前贪心最优的叶子,然后往上连接. 以下的贪心本蒟蒻并没有想出严格证明方法,只能感性理解一下了QAQ. 贪心 1:目前\(d_{v_u}\)最小的叶子\(u\)是最优叶子 举个栗子:\

CF461B Appleman and Tree (树DP)

CF462D Codeforces Round #263 (Div. 2) D Codeforces Round #263 (Div. 1) B B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Appleman has a tree with n vertices. Some of t

[leetcode-663-Equal Tree Partition]

Given a binary tree with n nodes, your task is to check if it's possible to partition the tree to two trees which have the equal sum of values after removing exactly one edge on the original tree. Example 1: Input: 5 / 10 10 / 2 3 Output: True Explan

CF 461B Appleman and Tree 树形DP

Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are colored white. Consider a set consisting of k (0 ≤ k < n) edges of Appleman's tree. If Appleman deletes these edges from the tree, then

Codeforces 461 B. Appleman and Tree

树形DP... B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices a

Codeforces Round #263 (Div. 2) D. Appleman and Tree(树形DP)

题目链接 D. Appleman and Tree time limit per test :2 seconds memory limit per test: 256 megabytes input :standard input output:standard output Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices a