HDU - 5156 Harry and Christmas tree
题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5156
题意 :
给一颗编号为1-n的以1为根的树, 已知有m个颜色的礼物分布在某些节点上(同一节点可以有多个),
问 : 对于编号从1-n的节点, 每一个节点对应子树上有多少颜色不同的礼物.
思路 :
一开始的想法是DFS记录节点序列, 再开vector记录每个节点上挂的礼物(同一节点上对颜色去重), 用树状数组统计一个区间内不同颜色的种类
但是由于记录位置的数组同样要开到二维, 超过了限制, 于是也开成vector, 果断超时
后来还是看discuss里边sxbk同学的代码才知道更好的解法
DFS记录序列不是节点序列, 而是将所有节点的全部颜色(已去重)都记录在序列内, 这样位置记录的数组可以只用一维
这道题收获挺大的, 对DFS序的思想理解深入了, 同时学习了 统计一个区间内有多少不同的数 这个问题的解法
题目代码 :
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = 5e4+;
const int MAXM = 5e5+; vector<int> edge[MAXN];
vector<int> gift[MAXN];
int seq[*MAXM];
int st[MAXN];
int ed[MAXN];
int s[*MAXM];
int mp[*MAXM];
int ans[MAXN];
int pos[MAXN];
int cnt, n, m; void Dfs(int u, int fa)
{
st[u] = cnt + ;
int num = gift[u].size();
for(int i = ; i < num; i++) {
seq[++cnt] = gift[u][i];
}
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) Dfs(v, u);
}
ed[u] = cnt;
} int Lowbit(int x)
{
return x & (-x);
} void Add(int x, int val)
{
for(int i = x; i <= cnt; i += Lowbit(i)) {
s[i] += val;
}
} int Sum(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s[i];
}
return res;
} bool cmp(int a, int b)
{
return ed[a] < ed[b];
} void Init()
{
for(int i = ; i <= n; i++) {
edge[i].clear();
gift[i].clear();
}
for(int i = ; i <= n; i++) {
pos[i] = i;
}
memset(s, , sizeof(s));
memset(mp, , sizeof(mp));
} int main()
{
int u, v; while(scanf("%d %d", &n, &m) != EOF) {
Init();
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
while(m--) {
scanf("%d %d", &u, &v);
if(find(gift[u].begin(), gift[u].end(), v) == gift[u].end()) {
gift[u].push_back(v);
}
}
cnt = ;
Dfs(, -);
sort(pos+, pos++n, cmp);
for(int i = ; i <= cnt; i++) {
if(mp[seq[i]] == ) {
Add(i, );
mp[seq[i]] = i; //如果是第一次出现, mp[seq[i]]记录为当前位置
}
}
int right = ;
for(int i = ; i <= n; i++) {
int now = pos[i];
while(right <= ed[now]) {
if(mp[seq[right]] != right) { //如果不是第一次出现
Add(mp[seq[right]], -); //减去前一次出现的
Add(right, );
mp[seq[right]] = right; //重新定义这个数最近一次出现位置
}
right++;
}
ans[now] = Sum(ed[now]) - Sum(st[now] - );
}
printf("%d", ans[]);
for(int i = ; i <= n; i++) {
printf(" %d", ans[i]);
}
printf("\n");
} return ;
}
另外第一次学习到 统计一个区间内有多少不同的数 这个问题的解法
基本思路是树状数组, 但是有重复的数, 要保证在一个区间内只更新过一次
所做的处理是用先遍历记录数字的数组a, 用数-位置数组 mp[a[i]] 来记录每个数第一次出现的位置并该点更新
这个操作对应的代码
for(int i = ; i <= n; i++) {
if(mp[a[i]] == ) { //如果是第一次出现, 记录第一次出现位置并更新
Add(i, );
mp[a[i]] = i;
}
}
记录左右查询, 每个查询按区间右端点R[i]从小到大排序
设一个扫描线k, 它的目的保证R[i]之前所有不同的点只更新过一次, 并且是在离R[i]最近的那个点更新
如此便可以写出这样一段代码
for(int i = ; i <= query_num; i++) {
while(k <= R[i]) {
if(mp[a[i]] != k) { //如果不是最新次出现
Add(mp[a[k]], -); //将上一次出现的更新-1
Add(k, ); //将这个位置新出现的更新1
mp[a[k]] = k; //更新这个数最近一次的位置
}
k++;
}
ans[i] = Sum(ed[i]) - Sum(st[i] - );
}
恩, 就是这样...
HDU - 5156 Harry and Christmas tree的更多相关文章
- POJ3013 Big Christmas Tree[转换 最短路]
Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 23387 Accepted: 5 ...
- poj 3013 Big Christmas Tree (最短路径Dijsktra) -- 第一次用优先队列写Dijsktra
http://poj.org/problem?id=3013 Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total S ...
- poj 3013 Big Christmas Tree Djistra
Big Christmas Tree 题意:图中每个节点和边都有权值,图中找出一颗树,树根为1使得 Σ(树中的节点到树根的距离)*(以该节点为子树的所有节点的权值之和) 结果最小: 分析:直接求出每个 ...
- hdu 4912 Paths on the tree(树链拆分+贪婪)
题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道.要求尽量选出多的通道,而且两两通道不想交. 解题思路:用树链剖分求LCA,然后依据通道两端节点的LC ...
- POJ 3013 Big Christmas Tree(最短Dijkstra+优先级队列优化,SPFA)
POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA) ACM 题目地址:POJ 3013 题意: 圣诞树是由n个节点和e个边构成的,点编号1-n. ...
- POJ Big Christmas Tree(最短的基础)
Big Christmas Tree 题目分析: 叫你构造一颗圣诞树,使得 (sum of weights of all descendant nodes) × (unit price of the ...
- poj 3013 Big Christmas Tree
Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 20974 Accepted: 4 ...
- Big Christmas Tree(poj-3013)最短路
Big Christmas Tree Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 25823 Accepted: 5 ...
- (hdu)5423 Rikka with Tree (dfs)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5423 Problem Description As we know, Rikka is p ...
随机推荐
- ViewPager 详解(四)----自主实现滑动指示条
前言:前面我们用了三篇的时间讲述了有关ViewPager的基础知识,到这篇就要进入点实际的了.在第三篇<ViewPager 详解(三)---PagerTabStrip与PagerTitleStr ...
- fork 和 vfork 的区别与联系
vfork用于创建一个新进程,而该新进程的目的是exec一个新进程,vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,不会复制页表.因为子进程会立即调用exec ...
- DELL R720服务器安装Windows Server 2008 R2 操作系统图文详解
DELL R720服务器安装Windows Server 2008 R2 操作系统图文详解 说明:此文章中部分图片为网络搜集,所以不一定为DELL R720服务器安装界面,但可保证界面内容接近DELL ...
- Gradle 用法总结
用过android studio的对gradle应该都不陌生了,gradle文件的基本配置大同小异,略做了解使用应该是没什么问题了.但是深入细致的了解一下对于理解项目还是很有帮助的,尤其是遇到一些配置 ...
- 大数据笔记03:大数据之Hadoop的安装
1.安装Hadoop (1)准备Linux环境 (2)安装JDK (3)配置Hadoop 2.准备Linux环境 (1)我们用户可能都是使用Windows环境,一般用户都是先安装虚拟机,然后在虚拟机上 ...
- GBK编码和UTF-8编码互转的大坑
这几天遇到一个BUG,问题很简单,解决却花了3.4天,特意记录下来. linux环境下,将默认编码设置为GBK以后,运行GBK编码的脚本,调用一个Java的jar包,然后总jar包中返回GBK字符串. ...
- python集合set,frozenset--笔记
<Python3程序开发指南>笔记. python提供了2种内置的集合类型:可变的set类型.固定的frozenset类型. 只有可哈希运算的对象可添加到集合中.可哈希的数据类型:floa ...
- jdbc01
1.创建对应的数据库以及表 /* SQLyog 企业版 - MySQL GUI v8.14 MySQL - 5.5.32-log : Database - news ***************** ...
- html:标签原本属性
<!doctype html>无标题文档 a标签,默认有text-decoration属性 span标签不需要清零 b标签不需要清零 em标签不需要清零 strong 相邻内嵌元素代码里面 ...
- 遍历页面上所有TextBox,并赋值为String.Empty
//不含母板页 foreach (System.Web.UI.Control txtobj in this.Page.Controls) { if (txtobj.GetType().Na ...