HDU 4358
看了题解那个弱化版后,马上就去做了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的更多相关文章
- HDU 4358 Boring counting(莫队+DFS序+离散化)
Boring counting Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others) ...
- HDU - 4358 Boring counting (dsu on tree)
Boring counting: http://acm.hdu.edu.cn/showproblem.php?pid=4358 题意: 求一棵树上,每个节点的子节点中,同一颜色出现k次 的 个数. 思 ...
- hdu 4358 Boring counting 离散化+dfs序+莫队算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4358 题意:以1为根节点含有N(N <= 1e5)个结点的树,每个节点有一个权值(weight ...
- hdu 4358 Boring counting dfs序+莫队+离散化
Boring counting Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others) ...
- HDU 4358 莫队算法+dfs序+离散化
Boring counting Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others)T ...
- HDU 4358 Boring counting 树状数组+思路
研究了整整一天orz……直接上官方题解神思路 #include <cstdio> #include <cstring> #include <cstdlib> #in ...
- HDU 4358 Boring counting dfs序+莫队算法
题意:N个节点的有根树,每个节点有一个weight.有Q个查询,问在以u为根的子树中,有恰好出现了K次的weight有多少种. 这是第一次写莫队算法,之前也只是偶有耳闻. 看了别人的代码打的,还是贴上 ...
- HDU - 4358 Boring counting (树上启发式合并/线段树合并)
题目链接 题意:统计树上每个结点中恰好出现了k次的颜色数. dsu on tree/线段树合并裸题. 启发式合并1:(748ms) #include<bits/stdc++.h> usin ...
- ACM数据结构相关资料整理【未完成,待补充】
在网上总是查不到很系统的练ACM需要学习的数据结构资料,于是参考看过的东西,自己整理了一份. 能力有限,欢迎大家指正补充. 分类主要参考<算法竞赛入门经典训练指南>(刘汝佳),山东大学数据 ...
随机推荐
- iOS8 tableView的Cell高度自适应开发
1.在- (void)viewDidLoad中设置: //估计高度为81 self.tableView.estimatedRowHeight = 81.0f; //自适应高度 self.tableVi ...
- 利用LruCache载入网络图片实现图片瀑布流效果(改进版)
PS: 2015年1月20日21:37:27 关于LoadImageAsyncTask和checkAllImageViewVisibility可能有点小bug 改动后的代码请參见升级版本号的代码 ht ...
- Gridview表格控件
Gridview表格控件 效果图: 分析: 使用和ListvVew很像,都是经过适配器将数据绑定到控件上 具体步骤如下: 1.创建GridView控件,并指定列数 android:numColumns ...
- hdoj--1151--Air Raid(最大独立集)
Air Raid Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- 二重积分的计算 —— 交换积分顺序(exchange the order of integration)
交换积分顺序的诀窍在数形结合: 1. 几句顺口溜 后积先定限,限内穿条线,先交下限写,后交上限见 先积 x,画横线(平行于 x 轴),右减左: 先积 y,画竖线(平行于 y 轴),上减下: 2. 简单 ...
- BZOJ 2794 DP
思路: 考虑把询问离线 按照m排序 物品按照a排序 f[i]表示c[j]的和到i b的最大值 背包就好 O(nk)竟然能过-- //By SiriusRen #include <cstdio&g ...
- 9.13[XJOI] NOIP训练32
今日9.13 洛谷打卡:小吉(今天心情不错,决定取消密码) (日常记流水账) 上午 今天听说是鏼鏼的题目,题面非常的清真啊,也没有当初以为的爆零啊 T1 排排坐 非常非常清真的模拟或是结论题,再次将难 ...
- Jquery 重置表单
1.重置表单回初始状态 $('#fromid')[0].reset(); 此方法一步到位,不需要一个个的去赋值为空
- SQLServer Union 和 Union All 在Insert 语句中的不同效果
如果不是发了那个帖子还不会像这样意外发现这两者的不同,好歹了也工作了一段时间,真是汗颜 上例子: 执行此条插入语句后,只会插入两条数据,因为会把完全重复的数据过滤掉 insert into tests ...
- MemCached总结三:PHP的memcached管理接口
在Web系统中应用MemCached缓存技术,必须使用客户端API(PHP)进行访问,这样才能将用户请求的动态数据,缓存到memcached服务器中,来减少对数据库的访问压力.PHP中提供了用于内存缓 ...