题目链接 : 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的更多相关文章

  1. POJ3013 Big Christmas Tree[转换 最短路]

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23387   Accepted: 5 ...

  2. poj 3013 Big Christmas Tree (最短路径Dijsktra) -- 第一次用优先队列写Dijsktra

    http://poj.org/problem?id=3013 Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total S ...

  3. poj 3013 Big Christmas Tree Djistra

    Big Christmas Tree 题意:图中每个节点和边都有权值,图中找出一颗树,树根为1使得 Σ(树中的节点到树根的距离)*(以该节点为子树的所有节点的权值之和) 结果最小: 分析:直接求出每个 ...

  4. hdu 4912 Paths on the tree(树链拆分+贪婪)

    题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道.要求尽量选出多的通道,而且两两通道不想交. 解题思路:用树链剖分求LCA,然后依据通道两端节点的LC ...

  5. POJ 3013 Big Christmas Tree(最短Dijkstra+优先级队列优化,SPFA)

    POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA) ACM 题目地址:POJ 3013 题意:  圣诞树是由n个节点和e个边构成的,点编号1-n. ...

  6. POJ Big Christmas Tree(最短的基础)

    Big Christmas Tree 题目分析: 叫你构造一颗圣诞树,使得 (sum of weights of all descendant nodes) × (unit price of the ...

  7. poj 3013 Big Christmas Tree

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 20974   Accepted: 4 ...

  8. Big Christmas Tree(poj-3013)最短路

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 25823   Accepted: 5 ...

  9. (hdu)5423 Rikka with Tree (dfs)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5423 Problem Description As we know, Rikka is p ...

随机推荐

  1. pat 1049. Counting Ones (30)

    看别人的题解懂了一些些    参考<编程之美>P132 页<1 的数目> #include<iostream> #include<stdio.h> us ...

  2. [Redux] Implementing Store from Scratch

    Learn how to build a reasonable approximation of the Redux Store in 20 lines. No magic! const counte ...

  3. android Json解析详解

    JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语 言的支持),从而可以在不同平台间进行数 ...

  4. Android中解析网络请求的URL

    近期正在做Android网络应用的开发,使用了android网络请求方面的知识.如今向大家介绍网络请求方面的知识.我们知道android中向server端发送一个请求,(这就是我们通常所说的POST请 ...

  5. ASP图片格式与base64数据互转方法

    ASP图片格式与base64数据相互转换的方法,经常用于处理表单中存储有base64字符串格式的图片. 获取到base64数据,转换成图片 <% Subfolder=year(now)& ...

  6. 无限循环的ViewPager

    目前情况 在不修改源码的情况下,当ViewPager滑动到最后一个item的时候,他就无法再往右滑动:当ViewPager滑动到第一个item的时候,他也无法再往前滑动.(以上全是废话) 设想 我们可 ...

  7. html图像入门

    在HTML中,图像由<img>标签定义. <img>是空标签,意思是说,它只包含属性,并且没有闭合标签. 要在页面上显示图像,需要使用源属性src, src指的是"s ...

  8. DHCP租约时间工作原理

    问题:    很多用户在使用路由器的DHCP服务器过程中都有一个疑问,DHCP有个设置项目是设置DHCP地址的租约时间,如果设置的比较短,是否会出现租约时间到了以后会重新去获取ip地址,造成用户断网? ...

  9. Jquery中dialog属性小记

    代码如下: $('#dialogDiv').dialog( { hide:true, //点击关闭是隐藏,如果不加这项,关闭弹窗后再点就会出错. autoOpen:false, height:380, ...

  10. javascript DOM对象转jquery对象

    首先,假设一种情形:要在HTML文件中为一个select对象添加一个函数,这个函数的名字叫dynamic_change(this),当select的option被改变的时候调用onchange事件来处 ...