HDU 4303 Hourai Jeweled 解题报告

HDU 4303 Hourai Jeweled 解题报告

评测地址: http://acm.hdu.edu.cn/showproblem.php?pid=4303

评测地址: https://xoj.red/contests/view/1155/1

题目描述

Kaguya Houraisan was once a princess of the Lunarians, a race of people living on the Moon. She was exiled to Earth over a thousand years ago for the crime of using the forbidden Hourai Elixir to make herself immortal. Tales of her unearthly beauty led men from all across the land to seek her hand in marriage, but none could successfully complete her trial of the Five Impossible Requests.

One of these requests is to reckon the value of "Hourai Jeweled (蓬莱の玉の枝)". The only one real treasure Kaguya has, in her possession. As showed in the picture, Hourai Jeweled is a tree-shaped twig. In which, each node is ornamented with a valuable diamond and each edge is painted with a briliant color (only bright man can distinguish the difference). Due to lunarians‘ eccentric taste, the value of this treasure is calculated as all the gorgeous roads‘ value it has. The road between two different nodes is said to be gorgeous, if and only if all the adjacent edges in this road has diffenrent color. And the value of this road is the sum of all the nodes‘ through the road.

Given the value of each node and the color of each edge. Could you tell Kaguya the value of her Hourai Jeweled?

输入格式

Input

The input consists of several test cases.

The first line of each case contains one integer N (1 <= N <= 300000), which is the number of nodes in Hourai Jeweled.

The second line contains N integers, the i-th of which is Vi (1 <= Vi <= 100000), the value of node i.

Each of the next N-1 lines contains three space-separated integer X, Y and Z (1<=X,Y<=N, 1 <= Z <= 100000), which represent that there is an edge between X and Y painted with colour Z.

输出格式

Output

For each test case, output a line containing the value of Hourai Jeweled.

样例输入输出

Sample Input

6

6 2 3 7 1 4

1 2 1

1 3 2

1 4 3

2 5 1

2 6 2

Sample Output

134

Hint

样例解释

gorgeous roads are :

1-2               Value: 8

1-3               Value: 9

1-4         Value:13

1-2-6          Value:12

2-1-3         Value:11

2-1-4    Value:15

2-5         Value:3

2-6               Value:6

3-1-4             Value:16

3-1-2-6        Value:15

4-1-2-6        Value:19

5-2-6            Value:7

版权信息

Author

BUPT

Source

2012 Multi-University Training Contest 1

Recommend

zhuyuanchen520   |   We have carefully selected several similar problems for you:  4300 4301 4302 4308 4304

题目翻译

题目描述:

一棵N个点的树,树上每个点有点权,每条边有颜色。一条路径的权值是这条路径上所有点的点权和,一条合法的路径需要满足该路径上任意相邻的两条边颜色都不相同。问这棵树上所有合法路径的权值和是多少啊?(无向路径)

输入格式:

第一行一个整数N,代表树上有多少个点。

接下来一行N个整数,代表树上每个点的权值。

接下来N-1行,每行三个整数S、E、C,代表S与E之间有一条颜色为C的边

输出格式:

一行一个整数,代表所求的值。

数据范围:

对与30%的数据,1≤N≤1000。

对于另外20%的数据,可用的颜色数不超过1e9且随机数据。

对于另外20%的数据,树的形态为一条链。

对于100%的数据,1≤N≤3e5,可用的颜色数不超过1e9,所有点权的大小不超过1e5。

题目解析(sol)

解析

l  Sub1 对于30%的数据,1≤N≤1000。

暴力dfs枚举所有链

复杂度: O(n^2)

程序:见后附1

l  Sub2 对于另外20%的数据,树的形态为一条链。

线性dp。

设f[i]表示到第i位的路径总长度,显然singma{f[i]|1<=i<=n}就是答案

另外设cnt[i]表示第i个点计入几次。

初始值:f[1]=0,由题意可知一个点不算

转移:

若上一条链和这一条链颜色一样,

cnt[i]=1,就是说前面的都不可以走到这个点上。

f[i]=w[r[i-1]]+w[r[i]];

若上一条链和这一条颜色不一样,

cnt[i]=cnt[i-1]+1,前面的点都可以走到这个点上

f[i]=f[i-1]+cnt[i]*w[r[i]]+w[r[i-1]]

复杂度:对于链的数据O(n),对于树的数据O(n^2)

程序:(见后附1)

l  Sub3 100%树形dp+统计

考虑两种可能:1.儿子到父亲的一条链

2.儿子跨过父亲到儿子

对于每个节点我们记录两个值就是:

1.这个节点可用子路径数量num[]

2.以节点为子树根向下链所有路径总长度dp[]

在考虑儿子跨过父亲到儿子的情况下我们发现暴力枚举每一个儿子是会T的,想到用到mpnum[col]表示和父节点相邻边为col色的路径条数,mpdp表示子节点和父亲连边为col色的点权和。

把两种情况分开来考虑。

  1. 儿子到父亲的一条链:

Dp[u]=Dp[u]+Dp[v]+val[u]*num[v] (lastcolor != nowcolor)

Dp[u]=Dp[u] (lastcolor == nowcolor)

  1. 儿子跨过父亲到儿子

其中s_Dp表示子树的Dp[u]的和,Num[u]表示子树总的经过次数,Ans是答案

Temp+=Dp[v]*(sum_Num-mpnum[a[i].col])+Num[v]*(S_Dp-mpdp[a[i].col])

Ans+=temp/2;

程序:(见后附2)

程序(Sub1+Sub2 : 50pts)

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int MAXN=3e5 + 10;
int w[MAXN],head[MAXN],n,ans=0,tot=0,tt=0,r[MAXN],du[MAXN],f[MAXN];
int cnt[MAXN];
bool vis[MAXN];
struct rec{
    int pre,to,col;
}a[MAXN];
struct cc{
    int from,to,val,id;
}node[MAXN];
map<pair<int,int>,int>mp;
void adde(int u,int v,int col)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    a[tot].col=col;
    head[u]=tot;
}
void dfs(int u,int co,int sum)
{
    vis[u]=true;  sum+=w[u];  ans+=sum;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (vis[v]) continue;
        if (co==a[i].col) continue;
        dfs(v,a[i].col,sum);
    }
}
void dfs2(int u)
{
    r[++tt]=u; vis[u]=true;
    for (int i=head[u];i;i=a[i].pre){
        int v=a[i].to; if (vis[v]) continue;
        dfs2(v);
    }
}
void work()
{
    memset(du,0,sizeof(du));
    for (int i=1;i<=n;i++) scanf("%lld",&w[i]);
    int u,v,col;
    for (int i=1;i<=n-1;i++) {
        scanf("%lld%lld%lld",&u,&v,&col);
        adde(u,v,col); adde(v,u,col);
        mp[make_pair(u,v)]=col;
        mp[make_pair(v,u)]=col;
        du[u]++,du[v]++;
    }
    int root=1;
    for (int i=1;i<=n;i++)
     if (du[i]==1) { root=i; break;}
    tt=0;  memset(vis,false,sizeof(vis));
    dfs2(root);
    f[1]=0; int lc=-1;
    for (int i=2;i<=n;i++){
        if (mp[make_pair(r[i-1],r[i])]!=lc) {
            cnt[i]=cnt[i-1]+1;
            f[i]=f[i-1]+w[r[i]]*cnt[i]+w[r[i-1]];
        }
        else cnt[i]=1,f[i]=w[r[i]]+w[r[i-1]];
        lc=mp[make_pair(r[i-1],r[i])];
    }
    int ans=0;
    for (int i=1;i<=n;i++) ans+=f[i];
    printf("%lld\n",ans);
}
signed main()
{
    scanf("%lld",&n);
    if (n>1000) { work(); return 0;}
    int t=0;
    for (int i=1;i<=n;i++) scanf("%lld",&w[i]),t+=w[i];
    int u,v,col;
    for (int i=1;i<=n-1;i++) {
        scanf("%lld%lld%lld",&u,&v,&col);
        adde(u,v,col); adde(v,u,col);
    }
    for (int i=1;i<=n;i++) {
        memset(vis,false,sizeof(vis));
        dfs(i,-1,0);
    }
    ans=(ans-t)/2;
    printf("%lld\n",ans);
    return 0;
}

程序(Sub3: 100 pts)

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int MAXN=3e5+10;
int n,val[MAXN],ans;
struct rec{
    int pre,to,col;
}a[2*MAXN];
int head[MAXN],tot=0;
int num[MAXN],dp[MAXN];
void adde(int u,int v,int col)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    a[tot].col=col;
    head[u]=tot;
}
void dfs(int u,int fa,int lc)
{
    num[u]=1; dp[u]=val[u];
    map<int,int> mpnum,mpdp;
    int s_Num=0,s_Dp=0,t=0;
    for (int i=head[u];i;i=a[i].pre){
        int v=a[i].to; if(v==fa) continue;
        dfs(v,u,a[i].col);
        t=dp[v]+val[u]*num[v];
        if (a[i].col!=lc) {
            num[u]+=num[v];
            dp[u]+=t;
        }
        s_Num+=num[v];
        s_Dp+=t;
        mpnum[a[i].col]+=num[v];
        mpdp[a[i].col]+=t;
    }
    ans+=s_Dp;
    int temp=0;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        temp+=dp[v]*(s_Num-mpnum[a[i].col])+num[v]*(s_Dp-mpdp[a[i].col]);
    }
    ans+=temp/2;
}
signed main()
{
    scanf("%lld",&n);
    for (int i=1;i<=n;i++) scanf("%lld",&val[i]);
    int u,v,col;
    for (int i=1;i<=n-1;i++) {
        scanf("%lld%lld%lld",&u,&v,&col);
        adde(u,v,col);
        adde(v,u,col);
    }
    dfs(1,0,-1);
    printf("%lld\n",ans);
    return 0;
 }

From:     HGOI

Name:ljc20020730

Date: 20181004

原文地址:https://www.cnblogs.com/ljc20020730/p/9745018.html

时间: 2024-08-04 16:28:26

HDU 4303 Hourai Jeweled 解题报告的相关文章

HDU 4303 Hourai Jeweled(树形DP)

http://acm.hdu.edu.cn/showproblem.php?pid=4303 题意:给出一棵树,树上的每一个节点都有一个权值,每条边有一个颜色,如果一条路径上相邻边的颜色都是不同的,那么它就是符合要求的.求出所有符合要求的路径上的节点的权值和. 思路:num[u]表示u节点下有几条符合要求的子树路径,sum[u]表示u为起点(或者终点也可以)往子树方向符合要求的路径权值和. 如图,u的父节点颜色为1,u->v的边颜色为2,那么此时u可以和v相连,num[v]就是v保留的路径数,这

HDU 4303 Hourai Jeweled 树形dp 所有路径点权和 dfs2次

题意: long long ans = 0; for(int i = 1; i <= n; i++) for(int j = i+1; j <= n; j++) ans += F(i,j); F(i,j)表示i点到j点路径上所有的点权和. 若i->j路径上存在2条相邻边边权相同则 F(i,j) = 0 问:ans的值. int乘法爆掉了我也醉了... 思路: 和网上的统计边方法不同,这里是用统计点出现的次数来计算 我们计算每个点i 出现的次数,则答案就是 i的次数*i的点权 =>

【树形DP】HDU 4303 Hourai Jeweled

通道 题意:给一个树,边有颜色,点有权值.满足路径上没有两个相邻边同色的路径是好的路径,求好的路径的(路径上的点的权值和)的总和 思路: 边权排序,从任意一点开始深搜,每颗子树搜索完毕之后向上返回pair<可以延伸到该点且最后一条边与由父节点到该点的边颜色不同的gorgeous边的条数 , 所有这种边分数的总和>每次深搜完一个子节点之后,增加的过这一点的gorgeous边的总分数为:    之前深搜的所有子节点向上返回的边数之和 * 当前子节点返回的分数 +    之前深搜的所有子节点向上返回

hdu 4956 Poor Hanamichi 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4956(它放在题库后面的格式有一点点问题啦,所以就把它粘下来,方便读者观看) 题目意思:给出一个范围 [l, r] 你, 问是否能从中找到一个数证明 Hanamichi’s solution 的解法是错的. Hanamichi’s solution 是这样的: 对于某个数 X,从右往左数它的每一位数字(假设第一位是从0开始数).它 偶数位的数字之和 -  奇数位的数字之和  = 3  而且 这个 X

hdu 1514 Free Candies 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1514 题目意思:有4堆糖果,每堆糖果有n个,从上到下排好,取糖果只能从上往下取,取完的糖果放在篮子里,篮子里最多放5个,如果篮子里有两个颜色相同的糖果则可以取走放进口袋里,问最多能取走多少对糖果放进口袋.n<=40, 糖果颜色最多20种. 这题是抄这个人滴:http://fudq.blog.163.com/blog/static/1913502382014239225290/ 有些地方看得不太懂,本

最小生成树,POJ和HDU几道题目的解题报告(基于自己写的模板)

首先POJ题目: 链接:1251 Jungle Roads 题目大意:纯求最小生成树,结果为最小权值边的和.采用邻接表 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <queue> 5 using namespace std; 6 7 #define maxn 30 //最大顶点个数 8 int n; //顶点数,边数 9 10 struct arcn

hdu 2544 最短路 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 题目意思:给出 n 个路口和 m 条路,每一条路需要 c 分钟走过.问从路口 1 到路口 n 需要的最短时间是多少. 这题是最短路的入门题,从理解d-i--j---k(wg自创的,呵呵)到默打到修改,搞左两日终于好了,哈哈哈~~~太感动了. 第一次错是 少了Dijkstra()函数中的 for (j = 1; j <= n; j++) . 第二次错是把vis[k=j]=1 写在了 if (!v

hdu acm 2844 Coins 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2844 题目意思:有A1,A2,...,An 这 n 种面值的钱,分别对应的数量是C1,C2,...,Cn.问根据这么多数量的钱 能组成多少个 <= m 的钱. 如果用多重背包来做,超时了...如果用记忆化搜索,还是...超时= =..... 这个方法是网上搜的,觉得好神奇,能看懂一些. 它是根据完全背包的思路做的,但是需要限制每种币种的使用数量,于是就多了个used[] 数组来记录了. ! f[j]

hdu acm 1114 Piggy-Bank 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1114 题目意思:给出一个空的猪仔钱ang 的重量E,和一个装满钱的猪仔钱ang 的重量F你,实质上能装入得钱的重量就是F - E.接着有n 种币种,每个币种有两个属性刻画:面值 + 重量.问恰好装满(注意关键词: 恰好)后,需要的钱的最少数量所对应的钱是多少(有点拗口= =.)拿第一组数据来说, 10 110 2 1 1 30 50 我们当然是用两张30 来填满这个只能装100重量的罐啦,如果都用面