F - Tree Intersection CSU - 1811

Bobo has a tree with n vertices numbered by 1,2,…,n and (n-1) edges. The i-th vertex has color c i, and the i-th edge connects vertices a i and b i.
Let C(x,y) denotes the set of colors in subtree rooted at vertex x deleting edge (x,y).
Bobo would like to know R_i which is the size of intersection of C(a i,b i) and C(bi,a i) for all 1≤i≤(n-1). (i.e. |C(a i,b i)∩C(b i,a i)|)

Input

The input contains at most 15 sets. For each set:
The first line contains an integer n (2≤n≤10 5).
The second line contains n integers c 1,c 2,…,c n (1≤c_i≤n).
The i-th of the last (n-1) lines contains 2 integers a i,b i (1≤a i,b i≤n).

OutputFor each set, (n-1) integers R 1,R 2,…,R n-1.Sample Input

4
1 2 2 1
1 2
2 3
3 4
5
1 1 2 1 2
1 3
2 3
3 5
4 5

Sample Output

1
2
1
1
1
2
1 题意:给一棵带有颜色的树,去掉某一条边后,他就变成了两个连通块,求这两个连通块的颜色交集的大小。(对每条边求一次)
思路:首先我们可以预处理出来整棵树的颜色,去掉一条边,就相当于一颗子树独立出来了,就变成了一颗子树,和剩余的树,可以将子树的颜色处理出来,然后剩余的那棵树的颜色也求出来了(等于整树 减去 子树)。
子树的话我们就可以用启发性合并去求颜色。但是要注意一下细节,看下代码吧。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=1e5+;
int n,m;
int mx,big,id,sum;
int col[maxn],deep[maxn],num[maxn],si[maxn],hson[maxn],cnt[maxn],ans[maxn];
int l[maxn],r[maxn];
vector<int>G[maxn]; void findhson(int x,int fa,int dep)//找到所有的重儿子,并求出其深度
{
si[x]=;
deep[x]=dep;
int len=G[x].size();
for(int i=;i<len;i++)
{
int t=G[x][i];
if(t!=fa)
{
findhson(t,x,dep+);
si[x]+=si[t];
deep[t]=deep[x]+;
if(si[t]>si[hson[x]])
hson[x]=t;
}
}
}
void cal(int x,int fa,int val)
{
cnt[col[x]]+=val;
if(cnt[col[x]]==)//如果新出现一种颜色就说明重合的数量多了一个
sum++;
if(cnt[col[x]]==num[col[x]])/*如果这个这个子树的该颜色数量等于整棵树的该
颜色数量,就说明两棵子树的重合数量减一*/
sum--;
int len=G[x].size();
for(int i=;i<len;i++)
{
int t=G[x][i];
if(t!=fa && t!=big)
cal(t,x,val);
}
}
void dfs(int x,int fa,int flag)
{
int len=G[x].size();
for(int i=;i<len;i++)
{
int t=G[x][i];
if(t!=fa && t!=hson[x])
dfs(t,x,);
}
if(hson[x])
{
dfs(hson[x],x,);
big=hson[x];
}
cal(x,fa,);
big=;
ans[x]=sum;
if(!flag)
{
cal(x,fa,-);
sum=;
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
big=;sum=;
for(int i=;i<=n;i++)
{
G[i].clear();
num[i]=si[i]=hson[i]=cnt[i]=ans[i]=;
}
for(int i=;i<=n;i++)
{
scanf("%d",&col[i]);
num[col[i]]++;//记录每个颜色的数量
}
int x,y;
for(int i=;i<n;i++)
{
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
l[i]=x;r[i]=y;//记录其子节点和父亲节点
}
findhson(,,);
dfs(,,);
for(int i=;i<n;i++)
{
int j;
if(deep[l[i]]>deep[r[i]])//这个看我等会传的图就知道为什么要比较一下了
j=l[i];
else
j=r[i];
printf("%d\n",ans[j]);
}
}
return ;
}

为什么要比较深度?因为我们根固定,我们启发式合并只会求方框内的那个子树的情况,而并不会求剩余的那块的子树的情况。所以在计算的时候选择深度高的那颗子树去进行计算才是正确的。

启发式合并CSU - 1811的更多相关文章

  1. csu oj 1811: Tree Intersection (启发式合并)

    题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1811 给你一棵树,每个节点有一个颜色.问删除一条边形成两棵子树,两棵子树有多少种颜色是有 ...

  2. CSU 1811: Tree Intersection(线段树启发式合并||map启发式合并)

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1811 题意:给出一棵树,每一个结点有一个颜色,然后依次删除树边,问每次删除树边之后,分开的两个 ...

  3. [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

  4. 【BZOJ3123】森林(主席树,启发式合并)

    题意:一个带点权的森林,要求维护以下操作: 1.询问路径上的点权K大值 2.两点之间连边 n,m<=80000 思路:如果树的结构不发生变化只需要维护DFS序 现在因为树的结构发生变化,要将两棵 ...

  5. BZOJ2888 资源运输(LCT启发式合并)

    这道题目太神啦! 我们考虑他的每一次合并操作,为了维护两棵树合并后树的重心,我们只好一个一个的把节点加进去.那么这样一来看上去似乎就是一次操作O(nlogn),但是我们拥有数据结构的合并利器--启发式 ...

  6. 【BZOJ 2733】【HNOI 2012】永无乡 Splay启发式合并

    启发式合并而已啦,, 调试时发现的错误点:insert后没有splay,把要拆开的树的点插入另一个树时没有把ch[2]和fa设为null,找第k大时没有先减k,,, 都是常犯的错误,比赛时再这么粗心就 ...

  7. 51nod 1515 明辨是非 并查集 + set + 启发式合并

    给n组操作,每组操作形式为x y p. 当p为1时,如果第x变量和第y个变量可以相等,则输出YES,并限制他们相等:否则输出NO,并忽略此次操作. 当p为0时,如果第x变量和第y个变量可以不相等,则输 ...

  8. [BZOJ 1483][HNOI 2009]梦幻补丁(有序表启发式合并)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1483 分析: 先将不同的颜色的出现位置从小到大用几条链表串起来,然后统计一下答案 对于 ...

  9. 【BZOJ-2809】dispatching派遣 Splay + 启发式合并

    2809: [Apio2012]dispatching Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2334  Solved: 1192[Submi ...

随机推荐

  1. [App Store Connect帮助]八、维护您的 App(3)将 App 恢复至 App Store

    如果您已将 App 从 App Store 中移除,之后创建了该 App 的一个新版本,那么即使新版本被“App 审核”批准,App 状态也仍会是“被开发者下架”.若要发布新版本,您必须首先将其恢复至 ...

  2. CentOS 7安装并设置启动图形桌面

    服务器端有时没有安装图形桌面,采用下面的步骤安装gnome桌面,并能够启动后进入图形桌面 1.安装图形环境 #yum grouplist#yum groupinstall 'GNOME Desktop ...

  3. springboot(十一)SpringBoot任务

    github地址: https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-service 1 ...

  4. iOS端样式错位

    在iOS端上点击的时候触发点会在当前元素上方,原因是在最外层使用了fixed定位,换成绝对或相对定位解决问题

  5. Luogu P1113 杂务 【拓扑排序】 By cellur925

    题目传送门 这题我们一看就知道是拓扑排序,然而在如何转化问题上花了大工夫,一个小时后最后还是无奈看了题解qwq. 显然我们可以对于每个任务,从他的前导任务到他连一条边,最后我们可以得到一个DAG.在这 ...

  6. 实现strcmp功能

    判断两个字符串的大小 #include <stdio.h> int my_strcmp(const char *str1,const char *str2) { //判断两个字符串是否为空 ...

  7. Styles and Themens(1)详述

    Styles and Themes IN THIS DOCUMENT Defining Styles Inheritance Style Properties Applying Styles and ...

  8. ORACLE数据库的备份分为物理备份和逻辑备份两种。

    物理备份是将实际组成数据库的操作系统文件从一处拷贝到另一处的备份过程,通常是从磁盘到磁带.可以使用 Oracle 的恢复管理器(Recovery Manager,RMAN)或操作系统命令进行数据库的物 ...

  9. Kali linux 2016.2(Rolling)里的枚举服务

    前言 枚举是一类程序,它允许用户从一个网络中收集某一类的所有相关服务.

  10. poj3662 Telephone Lines

    思路: 二分+最短路.最短路也可以用来计算从a到达b所需的边权不超过x的边的数量. 实现: #include <cstdio> #include <cmath> #includ ...