CSU 1811: Tree Intersection(线段树启发式合并||map启发式合并)
http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1811
题意:给出一棵树,每一个结点有一个颜色,然后依次删除树边,问每次删除树边之后,分开的两个连通块里面的颜色交集数是多少,即公有的颜色数。
思路:可以像树形DP一样,先处理出儿子结点,然后回溯的时候和儿子结点的子树合并,更新父结点的子树,然后更新父结点的答案。
枚举删除的边。以u为子树里面放的是某个颜色有多少,然后和一开始统计的某种颜色的总数比较,如果树里面这个颜色的数目小于这个颜色的总数,那么这个颜色就肯定有一些是在另一个连通块里面,那么就是公有的,对答案有贡献。
如果树里面这个颜色的数目为0或者等于这个颜色的总数,说明不是公有的,那么对答案就没贡献。
因为直接合并的话O(n^2)的复杂度太大,因此用启发式合并达到O(nlogn)。
写了两种方法,都很好理解。
线段树:空间不足,因此要动态开辟结点
#include <bits/stdc++.h>
using namespace std;
#define N 100010
struct node {
int val, cnt, l, r; // val是颜色c的个数,sum是答案的个数
} tree[N*];
struct Edge {
int v, nxt, id;
} edge[N*];
int n, col[N], sum[N], head[N], tot, sz, root[N], ans[N], e[N];
// 共有的就是交集就是答案
void Add(int u, int v, int id) {
edge[tot] = (Edge) { v, head[u], id }; head[u] = tot++;
edge[tot] = (Edge) { u, head[v], id }; head[v] = tot++;
} void PushUp(int now) {
tree[now].cnt = tree[tree[now].l].cnt + tree[tree[now].r].cnt;
} int Build(int l, int r, int c) {
int now = ++sz;
tree[now].l = tree[now].r = ;
int m = (l + r) >> ;
if(l == r) {
tree[now].val = ;
tree[now].cnt = (tree[now].val < sum[c] ? : );
return now;
}
if(c <= m) tree[now].l = Build(l, m, c);
else tree[now].r = Build(m + , r, c);
PushUp(now);
return now;
} void Merge(int &rt1, int rt2, int l, int r) {
if(!rt1 || !rt2) {
if(!rt1) rt1 = rt2; // 小的变成大的
return ;
}
if(l == r) {
tree[rt1].val += tree[rt2].val;
tree[rt1].cnt = (tree[rt1].val < sum[l] ? : );
return ;
}
int m = (l + r) >> ;
Merge(tree[rt1].l, tree[rt2].l, l, m);
Merge(tree[rt1].r, tree[rt2].r, m + , r);
PushUp(rt1);
} void DFS(int u, int fa, int id) {
root[u] = Build(, n, col[u]);
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(v == fa) continue;
DFS(v, u, edge[i].id);
Merge(root[u], root[v], , n);
}
if(id) e[id] = tree[root[u]].cnt;
} int main() {
while(~scanf("%d", &n)) {
memset(sum, , sizeof(sum));
for(int i = ; i <= n; i++) scanf("%d", &col[i]), sum[col[i]]++;
memset(head, -, sizeof(head)); sz = , tot = ;
for(int i = ; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
Add(u, v, i);
}
DFS(, -, );
for(int i = ; i < n; i++)
printf("%d\n", e[i]);
}
return ;
}
map:
#include <bits/stdc++.h>
using namespace std;
#define N 100010
struct Edge {
int v, nxt, id;
} edge[N*];
map<int, int> num[N];
int n, col[N], sum[N], cnt[N], e[N], head[N], tot; void Add(int u, int v, int id) {
edge[tot] = (Edge) { v, head[u], id }; head[u] = tot++;
edge[tot] = (Edge) { u, head[v], id }; head[v] = tot++;
} void DFS(int u, int fa, int id) {
num[u][col[u]] = ; cnt[u] = num[u][col[u]] < sum[col[u]] ? : ;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v, idd = edge[i].id;
if(v == fa) continue;
DFS(v, u, idd);
if(num[u].size() < num[v].size()) // 启发式合并
swap(num[u], num[v]), swap(cnt[u], cnt[v]);
for(map<int,int>::iterator it = num[v].begin(); it != num[v].end(); it++) {
int key = it->first, cc = it->second;
if(num[u][key] + cc < sum[key] && num[u][key] == ) cnt[u]++; // 如果之前没被算过,并且是共有的就要加上
if(num[u][key] + cc == sum[key] && num[u][key] > ) cnt[u]--; // 如果之前被算过,并且是特有的就要减去
num[u][key] += cc;
}
}
if(id) e[id] = cnt[u];
} int main() {
while(~scanf("%d", &n)) {
memset(sum, , sizeof(sum));
memset(cnt, , sizeof(cnt));
for(int i = ; i <= n; i++) scanf("%d", &col[i]), sum[col[i]]++, num[i].clear();
memset(head, -, sizeof(head)); tot = ;
for(int i = ; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
Add(u, v, i);
}
DFS(, -, );
for(int i = ; i < n; i++) printf("%d\n", e[i]);
}
return ;
}
CSU 1811: Tree Intersection(线段树启发式合并||map启发式合并)的更多相关文章
- 【树状数组】CSU 1811 Tree Intersection (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1811 题目大意: 一棵树,N(2<=N<=105)个节点,每个节点有一种颜 ...
- CSU 1811 Tree Intersection
莫队算法,$dfs$序. 题目要求计算将每一条边删除之后分成的两棵树的颜色的交集中元素个数. 例如删除$u->v$,我们只需知道以$v$为$root$的子树中有多少种不同的颜色(记为$qq$), ...
- BZOJ_2212_[Poi2011]Tree Rotations_线段树合并
BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...
- poj 2892---Tunnel Warfare(线段树单点更新、区间合并)
题目链接 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensiv ...
- hdu 5274 Dylans loves tree(LCA + 线段树)
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)
[BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...
- 【BZOJ2212】[Poi2011]Tree Rotations 线段树合并
[BZOJ2212][Poi2011]Tree Rotations Description Byteasar the gardener is growing a rare tree called Ro ...
- bzoj2212/3702 [Poi2011]Tree Rotations 线段树合并
Description Byteasar the gardener is growing a rare tree called Rotatus Informatikus. It has some in ...
- bzoj2212[Poi2011]Tree Rotations [线段树合并]
题面 bzoj ans = 两子树ans + min(左子在前逆序对数, 右子在前逆序对数) 线段树合并 #include <cstdio> #include <cstdlib> ...
随机推荐
- C#实现下载的几种方式举例
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Secu ...
- Winform入门见解
winform算是C#比较快速的入门的一个了,简单的控件拖拽然后写上每个控件对应的事件.然后就可以了.需要美观的点 可以用Skin皮肤就完成了.我们先不说复杂的,就来个普通的三层架构来增删改查 分页和 ...
- Python在windows下的服务程序
Python程序作为Windows服务启动,需要安装pywin32包.下载路径: 我是下载路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 ...
- SQLServer 使用sp_repldone标识所有未分发的事务为已分发
原文:SQLServer 使用sp_repldone标识所有未分发的事务为已分发 对于发布数据库的数据大量操作时,会使日志扫描并读取太多,会导致分发堵塞很久.也有一些解决方法,参考 <SqlSe ...
- 微信小程序把玩(九)scroll-view组件
原文:微信小程序把玩(九)scroll-view组件 scroll-view为滚动视图,分为水平滚动和垂直滚动.注意滚动视图垂直滚动时一定要设置高度否则的话scroll-view不会生效.滚动视图常用 ...
- C#根据对象的指定字段去除重复值
PersonInfo类: public class PersonInfo { public int Index; public string Name; public override string ...
- spring.net的简单使用(二)资源配置
主要对资源配置做进一步的解析. 对资源位置的配置是在spring节点的context下,resource节点配置. spring.net的资源是可以设置在三种不同的位置的, 1.配置文件中 <r ...
- delphi Stomp客户端连接 RabbitMQ(1)
最近公司想上个消息推送系统,网上搜了很多,因公司主要产品是Delphi,我选择了开源的RabbitMQ,Erlang语言开发,天生并行. 代码下载地址:delphistomp下载地址 windows上 ...
- 使用MinGW编译Boost,MSVC编译Boost的几种链接方式 good
1.下载Boost(http://www.boost.org) 我目前用的是1.61.0版本 2.将MinGW下的bin目录完整路径设置到系统环境变量Path中,保证cmd命令行能找到gcc,g++等 ...
- file.delete()与file.deleteOnExit(); 的区别
file.delete() //删除文件,删除的是创建File对象时指定与之关联创建的那个文件.这是一个立刻执行的操作 file.deleteOnExit(); //在JVM进程退出的时候删除 ...