看了题解那个弱化版后,马上就去做了HDU 3333这道题,发现有可用的地方。于是往这方面想,主要是处理如何确定一个数出现K次的问题。想到了从左往右把每个数出现的次数记下来,但感觉不是这样,呃,再看别人做的,真的是这样的--!

主要是处理一个数出现K次后的情况,把每个数出现的位置记录下来,当出现大于等于K次时,假设此时已出现sz个,则把sz-k这个位置加1,把之前的SZ-K-1的位置-2,使之状态是-1(因为之前刚好出现K次时就已加1)。于是当查询到右端点时,求出区间和,+1和-1刚好消去。需要注意的是,当SZ-K-2>=0时,应当把SZ-K-2之前为-1的位置置成0,即加1。这样结果才是正确的。

至于把树映射到数组,很简单,使用DFS+时间戳的方法就可以了,记录每个结点第一次出现的次序以及深搜完以该结点为根的子树的最后一个时间戳即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
#define LL __int64
#define lowbit(x) ((x)&(-x))
using namespace std; const int N=100100;
const int Q=100100; struct Query{
int l,r,Id;
Query(){}
Query(int ll,int rr,int d){
l=ll; r=rr; Id=d;
}
bool operator <(const Query &a)const{
if(r<a.r) return true;
return false;
}
};
Query query[Q];
LL su[N],ans[Q];
int num[N],val[N];
struct Node{
int bgn,en;
};
Node node[N];
vector<int>pos[N];
int n,k,q,tot,DEP; struct Edge{
int u,v,next;
}edge[N*2];
int head[N]; void addedge(int u,int v){
edge[tot].u=u;
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
} LL sum(int x){
if(x==0) return 0;
LL s=0;
for(;x;x-=lowbit(x)){
s+=su[x];
}
return s;
} void update(int x,LL w){
for(;x<=n;x+=lowbit(x))
su[x]+=w;
} void dfs(int u,int f){
++DEP;
node[u].bgn=DEP;
val[DEP]=num[u];
for(int e=head[u];e!=-1;e=edge[e].next){
int v=edge[e].v;
if(v!=f){
dfs(v,u);
}
}
node[u].en=DEP;
} int main(){
int T,t=0,u,v,cnt=0;
scanf("%d",&T);
while(++t<=T){
map<int,int>mp;
tot=0;DEP=0;
cnt=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
head[i]=-1;
su[i]=0;
pos[i].clear();
if(!mp[num[i]])
mp[num[i]]=++cnt;
}
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(1,0);
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&cnt);
query[i]=Query(node[cnt].bgn,node[cnt].en,i);
}
sort(query+1,query+1+q);
cnt=1;
int sz;
for(int i=1;i<=n;i++){
int t=mp[val[i]];
pos[t].push_back(i);
sz=pos[t].size();
if(sz>=k){
if(sz==k){
update(pos[t][sz-k],1);
}
else{
update(pos[t][sz-k-1],-2);
update(pos[t][sz-k],1);
}
if(sz-k-2>=0)
update(pos[t][sz-k-2],1);
}
while(query[cnt].r==i){
ans[query[cnt].Id]=sum(query[cnt].r)-sum(query[cnt].l-1);
cnt++;
}
}
printf("Case #%d:\n",t);
for(int i=1;i<=q;i++)
printf("%I64d\n",ans[i]);
if(t<T)
puts("");
}
return 0;
}

  

HDU 4358的更多相关文章

  1. HDU 4358 Boring counting(莫队+DFS序+离散化)

    Boring counting Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 98304/98304 K (Java/Others) ...

  2. HDU - 4358 Boring counting (dsu on tree)

    Boring counting: http://acm.hdu.edu.cn/showproblem.php?pid=4358 题意: 求一棵树上,每个节点的子节点中,同一颜色出现k次 的 个数. 思 ...

  3. hdu 4358 Boring counting 离散化+dfs序+莫队算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4358 题意:以1为根节点含有N(N <= 1e5)个结点的树,每个节点有一个权值(weight ...

  4. hdu 4358 Boring counting dfs序+莫队+离散化

    Boring counting Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 98304/98304 K (Java/Others) ...

  5. HDU 4358 莫队算法+dfs序+离散化

    Boring counting Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 98304/98304 K (Java/Others)T ...

  6. HDU 4358 Boring counting 树状数组+思路

    研究了整整一天orz……直接上官方题解神思路 #include <cstdio> #include <cstring> #include <cstdlib> #in ...

  7. HDU 4358 Boring counting dfs序+莫队算法

    题意:N个节点的有根树,每个节点有一个weight.有Q个查询,问在以u为根的子树中,有恰好出现了K次的weight有多少种. 这是第一次写莫队算法,之前也只是偶有耳闻. 看了别人的代码打的,还是贴上 ...

  8. HDU - 4358 Boring counting (树上启发式合并/线段树合并)

    题目链接 题意:统计树上每个结点中恰好出现了k次的颜色数. dsu on tree/线段树合并裸题. 启发式合并1:(748ms) #include<bits/stdc++.h> usin ...

  9. ACM数据结构相关资料整理【未完成,待补充】

    在网上总是查不到很系统的练ACM需要学习的数据结构资料,于是参考看过的东西,自己整理了一份. 能力有限,欢迎大家指正补充. 分类主要参考<算法竞赛入门经典训练指南>(刘汝佳),山东大学数据 ...

随机推荐

  1. 【BZOJ】2140 稳定婚姻

    [解析]Hash,离散化.Tarjan [分析] 对于每一个名字.首先离散化成编号. 用hash或者其它,反正不要最主要的即可了.否则O(N^2L)会爆掉. 然后请參考:http://www.cnbl ...

  2. laravel接口设计

    在各种公共方法都设计好,软件安装成功的条件下 routes/web.php中路由信息如下 <?php /* |------------------------------------------ ...

  3. NEU操作系统实验课4——线程同步

    实验要求: 创建两个线程按数字顺序打印10以下自然数,其中一个线程打印1-3及8-10:另一个线程打印4-6.要求使用线程同步机制实现上述打印顺序. 看网上的资料学习了两种写法 C++11的,使用了s ...

  4. TF-IDF算法--关键词句和文本集中每篇文章相关度计算

    关键词句和文本集每篇文章相关度计算:假设语料库中有几万篇文章,每篇文章的长度不一,你任意输入关键词或句子,通过代码以tf-idf值为准检索出来相似度高的文章. 1.TF-IDF概述 TF-IDF是一种 ...

  5. MD5三种方法的学习总结

    MD5百度百科 MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致.是计算机广泛使用的杂凑算法之一(又译摘要算法.哈希算法),主流编程语言普遍已 ...

  6. 控件——DataGridview

    控件:DataGridview    用来显示数据,      可以显示和编辑来自多种不同类型的数据源的表格数据. 一.两种显示数据的方式:手动,后台代码 主要通过后台代码:先建立三大类   然后绑定 ...

  7. 导入Excel时去除多余的空白行

    https://blog.csdn.net/shuishousuiyue/article/details/44773987 按着上面链接用的第一种方式,如下图所示:第二种方式要遍历每一个Excel单元 ...

  8. 第八周读书笔记(人月神话X月亮与六便士)——到底什么才是一个程序员的自我修养?

    写了这么久的读书笔记,涉及到问题大多是一些如何把软件工程做好,如何把自己的职业生涯做好.但总感觉逻辑链上缺了一环,亦即:我们为什么要把软件工程做好,我们成为一名优秀的职业生涯的意义到底在于什么?我觉得 ...

  9. 关于Java学习

    缘由 其实写东西的缘由都很简单,不外乎要总结记录,这里,是一种启明灯一样的东西. 虽然说是半路出家,但码代码也有不少时间了,学习编程也有记录可寻了.. 但是,但是,但是,到了工作中,虽然经前辈指点,仍 ...

  10. 洛谷P3958 奶酪 并查集

    两个空洞可互达当且仅当两个空洞相切,即球心距离小于等于球的直径. 一一枚举两个可互达的空洞,并用并查集连起来即可. Code: #include<cstdio> #include<c ...