HDU 6035 Colorful Tree dfs
2017-08-02 15:11
323 查看
题目
题目大意
给你一个数组,每一个点代表一种颜色,然后给你几条相邻路径,求每种颜色经过的路径的和,注意两个点以上叫路径,单个点不是路径
解题思路
反向思路,用总路径数减去每种颜色不可能经过的路径,所以只需要找出每一种颜色在图中不可能经过的联通块的大小就可以,这里用的dfs,具体看代码吧,感觉讲不明白,给师弟讲了半天自己感觉很受伤
先贴上一种很好想的思路
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define read(a) scanf("%d",&a)
#define Set(a,b) memset(a,b,sizeof(a))
const int mod=1e9+7;
const int maxn=200000+10;
int n;
LL ans;
int c[maxn],sum[maxn],siz[maxn];// sum数组存遍历到当前位置以本颜色为根的子树的和
bool vis[maxn];
int case_=1;
vector<int>e[maxn];
LL path(LL a)
{
return a*(a-1)/2;
}
void dfs(int x,int fa)
{
siz[x]=1;
int addsum=0;//遍历完所有子树,本颜色的子树增加的大小
for(auto &y:e[x])
{
if(y==fa)
continue;
int oldsum=sum[c[x]];
dfs(y,x);
int add=sum[c[x]]-oldsum; //增加的子树的大小
ans=ans+path((LL)siz[y]-(LL)add);
addsum+=add;
siz[x]+=siz[y];
}
sum[c[x]]+=siz[x]-addsum;
}
void work()
{
ans=0;
Set(c,0);
Set(sum,0);
Set(siz,0);
Set(vis,0);
int tot=0;
for(int i=1;i<=n;i++)
{
e[i].clear();
read(c[i]);
sum[c[i]]++;
if(sum[c[i]]==1)
tot++;
}
Set(sum,0);
int u,v;
for(int i=1;i<n;i++)
{
read(u);read(v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,-1);
vis[c[1]]=1;
for(int i=2;i<=n;i++)
{
if(!vis[c[i]])
{
ans+=path(n-sum[c[i]]);
vis[c[i]]=1;
}
}
LL myans=tot*path((LL)n)-ans;
printf("Case #%d: %lld\n",case_++,myans);
}
int main()
{
// freopen("1003.in", "r", stdin);
// freopen("data.out", "w", stdout);
while(~read(n))
{
work();
}
return 0;
}
这下面贴上标程,也是自己写的,可能和标程有点出入,不过思想来自标程
#include<cstdio>//c++ 11标准进行编译 auto move 不清楚请自行百度
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define read(a) scanf("%d",&a)
const int maxn=200000+10;
int L[maxn],R[maxn],n,siz[maxn],f[maxn];//L存的是第几个进入dfs,R存的是子树中(包括自己)在哪一个dfs出来的
vector<int> e[maxn],c[maxn];
int case_=1;
void dfs(int x,int fa, int && ncnt)
{
siz[x]=1; f[x]=fa;
L[x]=++ncnt;
for(auto y:e[x])
{
if(y==fa)
continue;
dfs(y,x,move(ncnt));
siz[x]+=siz[y];
}
R[x]=ncnt;
}
bool cmp(int x,int y)
{
return L[x]<L[y];
}
void work()
{
memset(L,0,sizeof(L));
memset(R,0,sizeof(R));
memset(siz,0,sizeof(siz));
for(int i=0;i<maxn;i++)
{
e[i].clear();
c[i].clear();
}
int x;
for(int i=1;i<=n;i++)
{
read(x);
c[x].push_back(i);
}
int u,v;
for(int i=1;i<n;i++)
{
read(u);read(v);
e[u].push_back(v);
e[v].push_back(u);
}
e[0].push_back(1);//建立虚根,不需要处理特殊情况
dfs(0,0,0);
LL res = (LL)n * n * (n - 1) / 2;
for(int i=1;i<=n;i++)
{
if(c[i].empty())
{
res -= (LL) n * (n - 1) / 2;
continue;
}
c[i].push_back(0);
sort(c[i].begin(),c[i].end(),cmp);
for(auto &x:c[i])
{
for(auto &y:e[x])
{
if(y==f[x])
continue;
int si=siz[y];
int k=L[y];
while(1)
{
L[n+1]=k;
auto it=lower_bound(c[i].begin(),c[i].end(),n+1,cmp);//返回根据cmp排序的一个大于等于"n+1"的数
if(it==c[i].end()||L[*it]>R[y])
break;
si-=siz[*it];
k=R[*it]+1;
}
res-=(LL)si*(LL)(si-1)/2;
}
}
}
printf("Case #%d: %lld\n" , case_++ , res);
}
int main()
{
// freopen("1003.in", "r", stdin);
//freopen("data.out", "w", stdout);
while(~read(n))
{
work();
}
return 0;
}
Colorful TreeTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2106 Accepted Submission(s): 897 Problem Description There is a tree with n nodes, each of which has a type of color represented by an integer, where the color of node i is ci. The path between each two different nodes is unique, of which we define the value as the number of different colors appearing in it. Calculate the sum of values of all paths on the tree that has n(n−1)2 paths in total. Input The input contains multiple test cases. For each test case, the first line contains one positive integers n, indicating the number of node. (2≤n≤200000) Next line contains n integers where the i-th integer represents ci, the color of node i. (1≤ci≤n) Each of the next n−1 lines contains two positive integers x,y (1≤x,y≤n,x≠y), meaning an edge between node x and node y. It is guaranteed that these edges form a tree. Output For each test case, output "Case #x: y" in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case. Sample Input 3 1 2 1 1 2 2 3 6 1 2 1 3 2 1 1 2 1 3 2 4 2 5 3 6 Sample Output Case #1: 6 Case #2: 29 |
给你一个数组,每一个点代表一种颜色,然后给你几条相邻路径,求每种颜色经过的路径的和,注意两个点以上叫路径,单个点不是路径
解题思路
反向思路,用总路径数减去每种颜色不可能经过的路径,所以只需要找出每一种颜色在图中不可能经过的联通块的大小就可以,这里用的dfs,具体看代码吧,感觉讲不明白,给师弟讲了半天自己感觉很受伤
先贴上一种很好想的思路
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define read(a) scanf("%d",&a)
#define Set(a,b) memset(a,b,sizeof(a))
const int mod=1e9+7;
const int maxn=200000+10;
int n;
LL ans;
int c[maxn],sum[maxn],siz[maxn];// sum数组存遍历到当前位置以本颜色为根的子树的和
bool vis[maxn];
int case_=1;
vector<int>e[maxn];
LL path(LL a)
{
return a*(a-1)/2;
}
void dfs(int x,int fa)
{
siz[x]=1;
int addsum=0;//遍历完所有子树,本颜色的子树增加的大小
for(auto &y:e[x])
{
if(y==fa)
continue;
int oldsum=sum[c[x]];
dfs(y,x);
int add=sum[c[x]]-oldsum; //增加的子树的大小
ans=ans+path((LL)siz[y]-(LL)add);
addsum+=add;
siz[x]+=siz[y];
}
sum[c[x]]+=siz[x]-addsum;
}
void work()
{
ans=0;
Set(c,0);
Set(sum,0);
Set(siz,0);
Set(vis,0);
int tot=0;
for(int i=1;i<=n;i++)
{
e[i].clear();
read(c[i]);
sum[c[i]]++;
if(sum[c[i]]==1)
tot++;
}
Set(sum,0);
int u,v;
for(int i=1;i<n;i++)
{
read(u);read(v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,-1);
vis[c[1]]=1;
for(int i=2;i<=n;i++)
{
if(!vis[c[i]])
{
ans+=path(n-sum[c[i]]);
vis[c[i]]=1;
}
}
LL myans=tot*path((LL)n)-ans;
printf("Case #%d: %lld\n",case_++,myans);
}
int main()
{
// freopen("1003.in", "r", stdin);
// freopen("data.out", "w", stdout);
while(~read(n))
{
work();
}
return 0;
}
这下面贴上标程,也是自己写的,可能和标程有点出入,不过思想来自标程
#include<cstdio>//c++ 11标准进行编译 auto move 不清楚请自行百度
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define read(a) scanf("%d",&a)
const int maxn=200000+10;
int L[maxn],R[maxn],n,siz[maxn],f[maxn];//L存的是第几个进入dfs,R存的是子树中(包括自己)在哪一个dfs出来的
vector<int> e[maxn],c[maxn];
int case_=1;
void dfs(int x,int fa, int && ncnt)
{
siz[x]=1; f[x]=fa;
L[x]=++ncnt;
for(auto y:e[x])
{
if(y==fa)
continue;
dfs(y,x,move(ncnt));
siz[x]+=siz[y];
}
R[x]=ncnt;
}
bool cmp(int x,int y)
{
return L[x]<L[y];
}
void work()
{
memset(L,0,sizeof(L));
memset(R,0,sizeof(R));
memset(siz,0,sizeof(siz));
for(int i=0;i<maxn;i++)
{
e[i].clear();
c[i].clear();
}
int x;
for(int i=1;i<=n;i++)
{
read(x);
c[x].push_back(i);
}
int u,v;
for(int i=1;i<n;i++)
{
read(u);read(v);
e[u].push_back(v);
e[v].push_back(u);
}
e[0].push_back(1);//建立虚根,不需要处理特殊情况
dfs(0,0,0);
LL res = (LL)n * n * (n - 1) / 2;
for(int i=1;i<=n;i++)
{
if(c[i].empty())
{
res -= (LL) n * (n - 1) / 2;
continue;
}
c[i].push_back(0);
sort(c[i].begin(),c[i].end(),cmp);
for(auto &x:c[i])
{
for(auto &y:e[x])
{
if(y==f[x])
continue;
int si=siz[y];
int k=L[y];
while(1)
{
L[n+1]=k;
auto it=lower_bound(c[i].begin(),c[i].end(),n+1,cmp);//返回根据cmp排序的一个大于等于"n+1"的数
if(it==c[i].end()||L[*it]>R[y])
break;
si-=siz[*it];
k=R[*it]+1;
}
res-=(LL)si*(LL)(si-1)/2;
}
}
}
printf("Case #%d: %lld\n" , case_++ , res);
}
int main()
{
// freopen("1003.in", "r", stdin);
//freopen("data.out", "w", stdout);
while(~read(n))
{
work();
}
return 0;
}
Colorful TreeTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2106 Accepted Submission(s): 897 Problem Description There is a tree with n nodes, each of which has a type of color represented by an integer, where the color of node i is ci. The path between each two different nodes is unique, of which we define the value as the number of different colors appearing in it. Calculate the sum of values of all paths on the tree that has n(n−1)2 paths in total. Input The input contains multiple test cases. For each test case, the first line contains one positive integers n, indicating the number of node. (2≤n≤200000) Next line contains n integers where the i-th integer represents ci, the color of node i. (1≤ci≤n) Each of the next n−1 lines contains two positive integers x,y (1≤x,y≤n,x≠y), meaning an edge between node x and node y. It is guaranteed that these edges form a tree. Output For each test case, output "Case #x: y" in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case. Sample Input 3 1 2 1 1 2 2 3 6 1 2 1 3 2 1 1 2 1 3 2 4 2 5 3 6 Sample Output Case #1: 6 Case #2: 29 |
相关文章推荐
- hdu 6035(Colorful Tree)
- hdu 6035(Colorful Tree)
- hdu 6035:Colorful Tree (2017 多校第一场 1003) 【树形dp】
- HDU-6035:Colorful Tree(虚树+DP)
- Colorful Tree(HDU 6035)
- Colorful Tree hdu 6035 (虚树,树形dp)
- HDU 2489 Minimal Ratio Tree(prim+dfs)
- hdu 2489 Minimal Ratio Tree【Dfs+kruskal】
- hdu 4836:The Query on the Tree(巧妙dfs序)
- hdu 6191 Query on A Tree(字典树启发式合并(动态建树) 可持久化字典树+dfs序)
- HDU 5416——CRB and Tree——————【DFS搜树】
- HDU 5416 CRB and Tree dfs
- hdu 2489 Minimal Ratio Tree dfs枚举组合情况+最小生成树★
- hdu 5379 Mahjong tree dfs
- HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)
- HDU 6035 Colorful Tree (2017多校1 - dfs思路)
- hdu 5423 Rikka with Tree(dfs)bestcoder #53 div2 1002
- HDU 5423 Rikka with Tree(简单DFS+枚举)
- 【DFS】HDU 5423 Rikka with Tree
- HDU 2489 Minimal Ratio Tree(DFS+prim)