题目链接

题意:统计树上每个结点中恰好出现了k次的颜色数。

dsu on tree/线段树合并裸题。

启发式合并1:(748ms)

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int n,m,k,a[N],b[N],nb,fa[N],son[N],siz[N],cnt[N],ans[N],now,ne,hd[N],ka;
struct E {int v,nxt;} e[N<<];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
void dfs1(int u,int f) {
fa[u]=f,son[u]=,siz[u]=;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u])continue;
dfs1(v,u),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void add(int x,int dx) {
if(cnt[x]==k)--now;
cnt[x]+=dx;
if(cnt[x]==k)++now;
}
void cal(int u,int x) {
add(a[u],x);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u])cal(v,x);
}
}
void dfs2(int u,int f) {
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]&&v!=son[u])dfs2(v,);
}
if(son[u])dfs2(son[u],);
add(a[u],);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]&&v!=son[u])cal(v,);
}
ans[u]=now;
if(!f) {
add(a[u],-);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u])cal(v,-);
}
}
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
if(ka)puts("");
printf("Case #%d:\n",++ka);
memset(hd,-,sizeof hd),ne=;
memset(cnt,,sizeof cnt);
memset(ans,,sizeof ans),now=;
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=n; ++i)b[i]=a[i];
sort(b+,b++n),nb=unique(b+,b++n)-(b+);
for(int i=; i<=n; ++i)a[i]=lower_bound(b+,b++nb,a[i])-b;
for(int i=; i<n; ++i) {
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
dfs1(,-),dfs2(,);
scanf("%d",&m);
while(m--) {
int u;
scanf("%d",&u);
printf("%d\n",ans[u]);
}
}
return ;
}

启发式合并2(加了dfs序的启发式合并,只比普通的快了一丁点):(702ms)

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int n,m,k,a[N],b[N],nb,fa[N],son[N],siz[N],cnt[N],ans[N],now,ne,hd[N],ka,tot,bg[N],ed[N],rnk[N];
struct E {int v,nxt;} e[N<<];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
void dfs1(int u,int f) {
fa[u]=f,son[u]=,siz[u]=,bg[u]=++tot,rnk[bg[u]]=u;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u])continue;
dfs1(v,u),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
ed[u]=tot;
}
void add(int x,int dx) {
if(cnt[x]==k)--now;
cnt[x]+=dx;
if(cnt[x]==k)++now;
}
void dfs2(int u,int f) {
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]&&v!=son[u])dfs2(v,);
}
if(son[u])dfs2(son[u],);
add(a[u],);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]&&v!=son[u])for(int i=bg[v]; i<=ed[v]; ++i)add(a[rnk[i]],);
}
ans[u]=now;
if(!f)for(int i=bg[u]; i<=ed[u]; ++i)add(a[rnk[i]],-);
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
if(ka)puts("");
printf("Case #%d:\n",++ka);
memset(hd,-,sizeof hd),ne=;
memset(cnt,,sizeof cnt),tot=;
memset(ans,,sizeof ans),now=;
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=n; ++i)b[i]=a[i];
sort(b+,b++n),nb=unique(b+,b++n)-(b+);
for(int i=; i<=n; ++i)a[i]=lower_bound(b+,b++nb,a[i])-b;
for(int i=; i<n; ++i) {
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
dfs1(,-),dfs2(,);
scanf("%d",&m);
while(m--) {
int u;
scanf("%d",&u);
printf("%d\n",ans[u]);
}
}
return ;
}

启发式合并3(map版,原理与普通启发式合并相同,轻链合并到重链上,重链中的父结点的贡献直接加进子结点):(1185ms)

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int n,m,k,a[N],b[N],F[N],nb,ans[N],ne,hd[N],ka,fa[N],son[N],siz[N];
map<int,int> mp[N];
struct E {int v,nxt;} e[N<<];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
void add(int u,int x,int dx) {
if(mp[F[u]][x]==k)--ans[u];
mp[F[u]][x]+=dx;
if(mp[F[u]][x]==k)++ans[u];
}
void mg(int u,int v) {
for(auto p:mp[F[v]])add(u,p.first,p.second);
mp[F[v]].clear();
}
void dfs1(int u,int f) {
fa[u]=f,son[u]=,siz[u]=;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u])continue;
dfs1(v,u),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u) {
F[u]=u;
if(son[u])dfs2(son[u]),ans[u]=ans[son[u]],F[u]=F[son[u]];
add(u,a[u],);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u]||v==son[u])continue;
dfs2(v),mg(u,v);
}
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
if(ka)puts("");
printf("Case #%d:\n",++ka);
memset(hd,-,sizeof hd),ne=;
memset(ans,,sizeof ans);
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=n; ++i)b[i]=a[i];
sort(b+,b++n),nb=unique(b+,b++n)-(b+);
for(int i=; i<=n; ++i)a[i]=lower_bound(b+,b++nb,a[i])-b;
for(int i=; i<n; ++i) {
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
dfs1(,-),dfs2(),mp[F[]].clear();
scanf("%d",&m);
while(m--) {
int u;
scanf("%d",&u);
printf("%d\n",ans[u]);
}
}
return ;
}

启发式合并4(map版,直接根据子树大小进行合并):(1263ms)

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int n,m,k,a[N],b[N],F[N],nb,ans[N],ne,hd[N],ka;
map<int,int> mp[N];
struct E {int v,nxt;} e[N<<];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
void add(int u,int x,int dx) {
if(mp[F[u]][x]==k)--ans[u];
mp[F[u]][x]+=dx;
if(mp[F[u]][x]==k)++ans[u];
}
void mg(int u,int v) {
if(mp[F[u]].size()<mp[F[v]].size())ans[u]=ans[v],swap(F[u],F[v]);
for(auto p:mp[F[v]])add(u,p.first,p.second);
mp[F[v]].clear();
}
void dfs(int u,int fa) {
add(F[u]=u,a[u],);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa)continue;
dfs(v,u),mg(u,v);
}
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
if(ka)puts("");
printf("Case #%d:\n",++ka);
memset(hd,-,sizeof hd),ne=;
memset(ans,,sizeof ans);
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=n; ++i)b[i]=a[i];
sort(b+,b++n),nb=unique(b+,b++n)-(b+);
for(int i=; i<=n; ++i)a[i]=lower_bound(b+,b++nb,a[i])-b;
for(int i=; i<n; ++i) {
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
dfs(,-),mp[F[]].clear();
scanf("%d",&m);
while(m--) {
int u;
scanf("%d",&u);
printf("%d\n",ans[u]);
}
}
return ;
}

线段树合并:(1014ms)

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int n,m,k,a[N],b[N],nb,ans[N],ne,hd[N],ka,tot,rt[N],ls[N*],rs[N*],val[N*],sum[N*];
#define mid ((l+r)>>1)
struct E {int v,nxt;} e[N<<];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
void pu(int u) {sum[u]=sum[ls[u]]+sum[rs[u]];}
int newnode() {int u=++tot; ls[u]=rs[u]=val[u]=sum[u]=; return u;}
void add(int& u,int x,int dx,int l=,int r=nb) {
if(!u)u=newnode();
if(l==r) {val[u]+=dx,sum[u]=val[u]==k; return;}
x<=mid?add(ls[u],x,dx,l,mid):add(rs[u],x,dx,mid+,r);
pu(u);
}
void mg(int& u,int v,int l=,int r=nb) {
if(!u||!v) {u=u|v; return;}
if(l==r) {val[u]+=val[v],sum[u]=val[u]==k; return;}
mg(ls[u],ls[v],l,mid),mg(rs[u],rs[v],mid+,r),pu(u);
}
void dfs(int u,int fa) {
rt[u]=,add(rt[u],a[u],);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa)continue;
dfs(v,u),mg(rt[u],rt[v]);
}
ans[u]=sum[rt[u]];
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
if(ka)puts("");
printf("Case #%d:\n",++ka);
memset(hd,-,sizeof hd),ne=;
memset(ans,,sizeof ans),tot=;
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=n; ++i)b[i]=a[i];
sort(b+,b++n),nb=unique(b+,b++n)-(b+);
for(int i=; i<=n; ++i)a[i]=lower_bound(b+,b++nb,a[i])-b;
for(int i=; i<n; ++i) {
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
dfs(,-);
scanf("%d",&m);
while(m--) {
int u;
scanf("%d",&u);
printf("%d\n",ans[u]);
}
}
return ;
}

还不够爽?再来个资瓷在线查询的可持久化线段树合并怎么样?就是有点吃内存。(1310ms)

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int n,m,k,a[N],b[N],nb,ne,hd[N],ka,tot,rt[N],ls[N*],rs[N*],val[N*],sum[N*];
#define mid ((l+r)>>1)
struct E {int v,nxt;} e[N<<];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
void pu(int u) {sum[u]=sum[ls[u]]+sum[rs[u]];}
int newnode() {int u=++tot; ls[u]=rs[u]=val[u]=sum[u]=; return u;}
void add(int& w,int u,int x,int dx,int l=,int r=nb) {
w=newnode();
if(l==r) {val[w]=val[u]+dx,sum[w]=val[w]==k; return;}
if(x<=mid)add(ls[w],ls[u],x,dx,l,mid),rs[w]=rs[u];
else add(rs[w],rs[u],x,dx,mid+,r),ls[w]=ls[u];
pu(w);
}
void mg(int& w,int u,int v,int l=,int r=nb) {
if(!u||!v) {w=u|v; return;}
w=newnode();
if(l==r) {val[w]=val[u]+val[v],sum[w]=val[w]==k; return;}
mg(ls[w],ls[u],ls[v],l,mid),mg(rs[w],rs[u],rs[v],mid+,r),pu(w);
}
void dfs(int u,int fa) {
rt[u]=,add(rt[u],rt[u],a[u],);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa)continue;
dfs(v,u),mg(rt[u],rt[u],rt[v]);
}
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
if(ka)puts("");
printf("Case #%d:\n",++ka);
memset(hd,-,sizeof hd),ne=;
tot=;
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=n; ++i)b[i]=a[i];
sort(b+,b++n),nb=unique(b+,b++n)-(b+);
for(int i=; i<=n; ++i)a[i]=lower_bound(b+,b++nb,a[i])-b;
for(int i=; i<n; ++i) {
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
dfs(,-);
scanf("%d",&m);
while(m--) {
int u;
scanf("%d",&u);
printf("%d\n",sum[rt[u]]);
}
}
return ;
}

HDU - 4358 Boring counting (树上启发式合并/线段树合并)的更多相关文章

  1. 洛谷P3605 [USACO17JAN] Promotion Counting 晋升者计数 [线段树合并]

    题目传送门 Promotion Counting 题目描述 The cows have once again tried to form a startup company, failing to r ...

  2. hdu 5511 Minimum Cut-Cut——分类讨论思想+线段树合并

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5511 题意:割一些边使得无向图变成不连通的,并且恰好割了两条给定生成树上的边.满足非树边两段一定在给定生成 ...

  3. 启发式合并 splay合并 线段树合并基础

    Gold is everywhen! - somebody 启发式合并 将小的集合一个个插入到大的集合. 每次新集合大小至少比小集合大一倍,因此每个元素最多合并\(\log n\)次,总复杂度为\(n ...

  4. 启发式合并&线段树合并/分裂&treap合并&splay合并

    启发式合并 有\(n\)个集合,每次让你合并两个集合,或询问一个集合中是否存在某个元素. ​ 我们可以用平衡树/set维护集合. ​ 对于合并两个\(A,B\),如果\(|A|<|B|\),那么 ...

  5. [BZOJ2733][HNOI2010]永无乡 解题报告 启发式合并,线段树合并

    好久没更新博客了,前段时间一直都在考试,都没时间些,现在终于有点闲了(cai guai)... 写了一道题,[HNOI2012]永无乡,其实是一道板子题,我发现我写了好多板子题...还是太菜了... ...

  6. bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

    这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例, ...

  7. Luogu5327【ZJOI2019】语言【树上差分,线段树合并】

    题目大意 给定一棵$n$个节点的树,维护$n$个集合,一开始第$i$个集合只有节点$i$.有$m$个操作,每次操作输入一个$(u,v)$,表示将$(u,v)$这条链上所有点所属的集合合并.求有多少个无 ...

  8. 5.20 省选模拟赛 T1 图 启发式合并 线段树合并 染色计数问题

    LINK:图 在说这道题之前吐槽一下今天的日子 520 = 1+1+4+514. /cy 这道题今天做的非常失败 一点分都没拿到手 关键是今天的T3 把我整个人给搞崩了. 先考虑 如果得到了这么一张图 ...

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

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

随机推荐

  1. HTML5 WebRTC API无需网络获取本地IP

    因需求需要获取客户端的本机IP,国内资料基本上都是通过向一个IP网站发送请求并获取IP,这样有一定几率泄露自己的IP,在内网环境下也并不适用. 后来在stackoverflow上找到一种解决办法,用W ...

  2. Prometheus告警模型分析

    Prometheus作为时下最为流行的开源监控系统,其庞大的生态体系:包括针对各种传统应用的Exporter,完整的二次开发工具链,与Kubernetes等主流平台的高度亲和以及由此带来的强大的自发现 ...

  3. 重叠IO 模型

    1. 重叠模型的优点 2. 重叠模型的基本原理 3. 关于重叠模型的基础知识 4. 重叠模型的实现步骤 5. 多客户端情况的注意事项 一.重叠模型的优点   1.可以运行在支持Winsock2的所有W ...

  4. win10更新导致chrome打开网页速度太慢

    升级win10之后如果出现chrome内核的浏览器网页总是打不开 打开很慢 而ie和edge是可以正常访问的 用这个方法可以 我弄了几天终于 搞好了 我直接转载过来了 近期,工程师收到大量反馈360浏 ...

  5. python基本成分详解

    字符串 一.需要了解的 msg = 'HelloWorld' 1.isdecimal判断是否是十进制(整数)w print(msg.isdecimal()) 2.endswith判断字符串末尾是否是指 ...

  6. MySQL 服务正在启动 MySQL 服务无法启动解决途径

    解决方案: 1.删除自己手动创建的data文件夹: 2.管理员权限CMD的bin目录下,移除已错误安装的mysqld服务: mysqld -remove MySQL出现删除成功! 3.在CMD的bin ...

  7. CVPR2019 论文解读| BASNet:关注边界的显著性目标检测

    作者 | 文永亮 学校 | 哈尔滨工业大学(深圳) 研究方向 | 目标检测 概要 ​ 这是一篇发表于CVPR2019的关于显著性目标检测的paper,<BASNet:Boundary-Aware ...

  8. 开启sentry权限控制hue

    参考: cloudera官方授权:包括webui, ldap,sentry https://www.cloudera.com/documentation/enterprise/6/6.2/topics ...

  9. LayaAir疑难杂症之四:laya引擎自动断点到bundle.js文件中且无报错,但程序不再执行

    在一次断点调试中,突然程序不再按照博主指定的断点执行,莫名其妙端点到了bundle.js文件中的某一行中,这是不应该的,第一次时间反应就是引擎出了问题,但是总不能让博主卸载重装吧. 经过查找资料,询问 ...

  10. urllib:处理网络异常

    from urllib import request, error import ssl import urllib.request import socket import urllib.error ...