HDU - 4358 Boring counting (树上启发式合并/线段树合并)
题意:统计树上每个结点中恰好出现了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 (树上启发式合并/线段树合并)的更多相关文章
- 洛谷P3605 [USACO17JAN] Promotion Counting 晋升者计数 [线段树合并]
题目传送门 Promotion Counting 题目描述 The cows have once again tried to form a startup company, failing to r ...
- hdu 5511 Minimum Cut-Cut——分类讨论思想+线段树合并
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5511 题意:割一些边使得无向图变成不连通的,并且恰好割了两条给定生成树上的边.满足非树边两段一定在给定生成 ...
- 启发式合并 splay合并 线段树合并基础
Gold is everywhen! - somebody 启发式合并 将小的集合一个个插入到大的集合. 每次新集合大小至少比小集合大一倍,因此每个元素最多合并\(\log n\)次,总复杂度为\(n ...
- 启发式合并&线段树合并/分裂&treap合并&splay合并
启发式合并 有\(n\)个集合,每次让你合并两个集合,或询问一个集合中是否存在某个元素. 我们可以用平衡树/set维护集合. 对于合并两个\(A,B\),如果\(|A|<|B|\),那么 ...
- [BZOJ2733][HNOI2010]永无乡 解题报告 启发式合并,线段树合并
好久没更新博客了,前段时间一直都在考试,都没时间些,现在终于有点闲了(cai guai)... 写了一道题,[HNOI2012]永无乡,其实是一道板子题,我发现我写了好多板子题...还是太菜了... ...
- bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)
这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例, ...
- Luogu5327【ZJOI2019】语言【树上差分,线段树合并】
题目大意 给定一棵$n$个节点的树,维护$n$个集合,一开始第$i$个集合只有节点$i$.有$m$个操作,每次操作输入一个$(u,v)$,表示将$(u,v)$这条链上所有点所属的集合合并.求有多少个无 ...
- 5.20 省选模拟赛 T1 图 启发式合并 线段树合并 染色计数问题
LINK:图 在说这道题之前吐槽一下今天的日子 520 = 1+1+4+514. /cy 这道题今天做的非常失败 一点分都没拿到手 关键是今天的T3 把我整个人给搞崩了. 先考虑 如果得到了这么一张图 ...
- HDU 4358 Boring counting(莫队+DFS序+离散化)
Boring counting Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others) ...
随机推荐
- ControlTemplate in WPF —— Checkbox
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" x ...
- redis cluster 集群 安装 配置 详解
redis cluster 集群 安装 配置 详解 张映 发表于 2015-05-01 分类目录: nosql 标签:cluster, redis, 安装, 配置, 集群 Redis 集群是一个提供在 ...
- 阶段3 2.Spring_06.Spring的新注解_1 spring的新注解-Configuration和ComponentScan
解决测试类重复代码的问题,xml还是存在的问题,没法脱离xml文件 要想在QueryRunner上加注解,是加不了的 创建工程 复制依赖项到pom.xml 复制注解的工程里面的com文件夹 配置文件b ...
- 工具栏对象GUI Status 与GUI Title
GUI Status 与GUI Title用于自定义工具栏按钮及Report程序标题栏显示内容, 可以通过se41\SE80或直接SE38中展开对象列表进行相关操作. 如下是在SE38里,点击[显示物 ...
- 将训练好的tensorflow模型移植到android应用中
具体步骤如下: 1. TFLiteConverter保存模型 修改网络模型代码,将模型通过TFLiteConverter转化成为 TensorFlow Lite FlatBuffer即为.tflit ...
- C#打开文件
C#中经常用到的功能,打开文件: /// <summary> /// 打开文件,可选择多个文件 /// </summary> /// <param name=" ...
- beego 注解路由
场景描述:使用注解路由,不起作用. 额外描述: 路由的添加都写在 main函数中了,同时未设置 beego.BConfig.RunMode ="dev"也未引入 :routers包 ...
- goland搭建beego开发环境
1.安装最新的go软件 ,当前版本1.122.下载goland开发工具3.安装bee工具 go get github.com/beego/bee4.通过bee api dsh -tables=&quo ...
- AGC037 C Numbers on a Circle【思维】
题目传送门 题意 这道题被某大佬改编拿来出成考试题,是长这个样子的: 好的,其实这才是真正的题意: 给定初始序列和最终序列,每次选择一个数变成自己和相邻2个数的和.问初始序列是否可以变为最终序列,若可 ...
- 手把手带你发布Nuget包-图文说话
博客:https://www.cnblogs.com/24klr/