HDU - 4358 Boring counting (树上启发式合并/线段树合并)
题意:统计树上每个结点中恰好出现了k次的颜色数。
dsu on tree/线段树合并裸题。
启发式合并1:(748ms)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 int n,m,k,a[N],b[N],nb,fa[N],son[N],siz[N],cnt[N],ans[N],now,ne,hd[N],ka; 6 struct E {int v,nxt;} e[N<<1]; 7 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 8 void dfs1(int u,int f) { 9 fa[u]=f,son[u]=0,siz[u]=1; 10 for(int i=hd[u]; ~i; i=e[i].nxt) { 11 int v=e[i].v; 12 if(v==fa[u])continue; 13 dfs1(v,u),siz[u]+=siz[v]; 14 if(siz[v]>siz[son[u]])son[u]=v; 15 } 16 } 17 void add(int x,int dx) { 18 if(cnt[x]==k)--now; 19 cnt[x]+=dx; 20 if(cnt[x]==k)++now; 21 } 22 void cal(int u,int x) { 23 add(a[u],x); 24 for(int i=hd[u]; ~i; i=e[i].nxt) { 25 int v=e[i].v; 26 if(v!=fa[u])cal(v,x); 27 } 28 } 29 void dfs2(int u,int f) { 30 for(int i=hd[u]; ~i; i=e[i].nxt) { 31 int v=e[i].v; 32 if(v!=fa[u]&&v!=son[u])dfs2(v,0); 33 } 34 if(son[u])dfs2(son[u],1); 35 add(a[u],1); 36 for(int i=hd[u]; ~i; i=e[i].nxt) { 37 int v=e[i].v; 38 if(v!=fa[u]&&v!=son[u])cal(v,1); 39 } 40 ans[u]=now; 41 if(!f) { 42 add(a[u],-1); 43 for(int i=hd[u]; ~i; i=e[i].nxt) { 44 int v=e[i].v; 45 if(v!=fa[u])cal(v,-1); 46 } 47 } 48 } 49 int main() { 50 int T; 51 for(scanf("%d",&T); T--;) { 52 if(ka)puts(""); 53 printf("Case #%d:\n",++ka); 54 memset(hd,-1,sizeof hd),ne=0; 55 memset(cnt,0,sizeof cnt); 56 memset(ans,0,sizeof ans),now=0; 57 scanf("%d%d",&n,&k); 58 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 59 for(int i=1; i<=n; ++i)b[i]=a[i]; 60 sort(b+1,b+1+n),nb=unique(b+1,b+1+n)-(b+1); 61 for(int i=1; i<=n; ++i)a[i]=lower_bound(b+1,b+1+nb,a[i])-b; 62 for(int i=1; i<n; ++i) { 63 int u,v; 64 scanf("%d%d",&u,&v); 65 addedge(u,v),addedge(v,u); 66 } 67 dfs1(1,-1),dfs2(1,1); 68 scanf("%d",&m); 69 while(m--) { 70 int u; 71 scanf("%d",&u); 72 printf("%d\n",ans[u]); 73 } 74 } 75 return 0; 76 }
启发式合并2(加了dfs序的启发式合并,只比普通的快了一丁点):(702ms)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 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]; 6 struct E {int v,nxt;} e[N<<1]; 7 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 8 void dfs1(int u,int f) { 9 fa[u]=f,son[u]=0,siz[u]=1,bg[u]=++tot,rnk[bg[u]]=u; 10 for(int i=hd[u]; ~i; i=e[i].nxt) { 11 int v=e[i].v; 12 if(v==fa[u])continue; 13 dfs1(v,u),siz[u]+=siz[v]; 14 if(siz[v]>siz[son[u]])son[u]=v; 15 } 16 ed[u]=tot; 17 } 18 void add(int x,int dx) { 19 if(cnt[x]==k)--now; 20 cnt[x]+=dx; 21 if(cnt[x]==k)++now; 22 } 23 void dfs2(int u,int f) { 24 for(int i=hd[u]; ~i; i=e[i].nxt) { 25 int v=e[i].v; 26 if(v!=fa[u]&&v!=son[u])dfs2(v,0); 27 } 28 if(son[u])dfs2(son[u],1); 29 add(a[u],1); 30 for(int i=hd[u]; ~i; i=e[i].nxt) { 31 int v=e[i].v; 32 if(v!=fa[u]&&v!=son[u])for(int i=bg[v]; i<=ed[v]; ++i)add(a[rnk[i]],1); 33 } 34 ans[u]=now; 35 if(!f)for(int i=bg[u]; i<=ed[u]; ++i)add(a[rnk[i]],-1); 36 } 37 int main() { 38 int T; 39 for(scanf("%d",&T); T--;) { 40 if(ka)puts(""); 41 printf("Case #%d:\n",++ka); 42 memset(hd,-1,sizeof hd),ne=0; 43 memset(cnt,0,sizeof cnt),tot=0; 44 memset(ans,0,sizeof ans),now=0; 45 scanf("%d%d",&n,&k); 46 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 47 for(int i=1; i<=n; ++i)b[i]=a[i]; 48 sort(b+1,b+1+n),nb=unique(b+1,b+1+n)-(b+1); 49 for(int i=1; i<=n; ++i)a[i]=lower_bound(b+1,b+1+nb,a[i])-b; 50 for(int i=1; i<n; ++i) { 51 int u,v; 52 scanf("%d%d",&u,&v); 53 addedge(u,v),addedge(v,u); 54 } 55 dfs1(1,-1),dfs2(1,1); 56 scanf("%d",&m); 57 while(m--) { 58 int u; 59 scanf("%d",&u); 60 printf("%d\n",ans[u]); 61 } 62 } 63 return 0; 64 }
启发式合并3(map版,原理与普通启发式合并相同,轻链合并到重链上,重链中的父结点的贡献直接加进子结点):(1185ms)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 int n,m,k,a[N],b[N],F[N],nb,ans[N],ne,hd[N],ka,fa[N],son[N],siz[N]; 6 map<int,int> mp[N]; 7 struct E {int v,nxt;} e[N<<1]; 8 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 9 void add(int u,int x,int dx) { 10 if(mp[F[u]][x]==k)--ans[u]; 11 mp[F[u]][x]+=dx; 12 if(mp[F[u]][x]==k)++ans[u]; 13 } 14 void mg(int u,int v) { 15 for(auto p:mp[F[v]])add(u,p.first,p.second); 16 mp[F[v]].clear(); 17 } 18 void dfs1(int u,int f) { 19 fa[u]=f,son[u]=0,siz[u]=1; 20 for(int i=hd[u]; ~i; i=e[i].nxt) { 21 int v=e[i].v; 22 if(v==fa[u])continue; 23 dfs1(v,u),siz[u]+=siz[v]; 24 if(siz[v]>siz[son[u]])son[u]=v; 25 } 26 } 27 void dfs2(int u) { 28 F[u]=u; 29 if(son[u])dfs2(son[u]),ans[u]=ans[son[u]],F[u]=F[son[u]]; 30 add(u,a[u],1); 31 for(int i=hd[u]; ~i; i=e[i].nxt) { 32 int v=e[i].v; 33 if(v==fa[u]||v==son[u])continue; 34 dfs2(v),mg(u,v); 35 } 36 } 37 int main() { 38 int T; 39 for(scanf("%d",&T); T--;) { 40 if(ka)puts(""); 41 printf("Case #%d:\n",++ka); 42 memset(hd,-1,sizeof hd),ne=0; 43 memset(ans,0,sizeof ans); 44 scanf("%d%d",&n,&k); 45 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 46 for(int i=1; i<=n; ++i)b[i]=a[i]; 47 sort(b+1,b+1+n),nb=unique(b+1,b+1+n)-(b+1); 48 for(int i=1; i<=n; ++i)a[i]=lower_bound(b+1,b+1+nb,a[i])-b; 49 for(int i=1; i<n; ++i) { 50 int u,v; 51 scanf("%d%d",&u,&v); 52 addedge(u,v),addedge(v,u); 53 } 54 dfs1(1,-1),dfs2(1),mp[F[1]].clear(); 55 scanf("%d",&m); 56 while(m--) { 57 int u; 58 scanf("%d",&u); 59 printf("%d\n",ans[u]); 60 } 61 } 62 return 0; 63 }
启发式合并4(map版,直接根据子树大小进行合并):(1263ms)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 int n,m,k,a[N],b[N],F[N],nb,ans[N],ne,hd[N],ka; 6 map<int,int> mp[N]; 7 struct E {int v,nxt;} e[N<<1]; 8 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 9 void add(int u,int x,int dx) { 10 if(mp[F[u]][x]==k)--ans[u]; 11 mp[F[u]][x]+=dx; 12 if(mp[F[u]][x]==k)++ans[u]; 13 } 14 void mg(int u,int v) { 15 if(mp[F[u]].size()<mp[F[v]].size())ans[u]=ans[v],swap(F[u],F[v]); 16 for(auto p:mp[F[v]])add(u,p.first,p.second); 17 mp[F[v]].clear(); 18 } 19 void dfs(int u,int fa) { 20 add(F[u]=u,a[u],1); 21 for(int i=hd[u]; ~i; i=e[i].nxt) { 22 int v=e[i].v; 23 if(v==fa)continue; 24 dfs(v,u),mg(u,v); 25 } 26 } 27 int main() { 28 int T; 29 for(scanf("%d",&T); T--;) { 30 if(ka)puts(""); 31 printf("Case #%d:\n",++ka); 32 memset(hd,-1,sizeof hd),ne=0; 33 memset(ans,0,sizeof ans); 34 scanf("%d%d",&n,&k); 35 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 36 for(int i=1; i<=n; ++i)b[i]=a[i]; 37 sort(b+1,b+1+n),nb=unique(b+1,b+1+n)-(b+1); 38 for(int i=1; i<=n; ++i)a[i]=lower_bound(b+1,b+1+nb,a[i])-b; 39 for(int i=1; i<n; ++i) { 40 int u,v; 41 scanf("%d%d",&u,&v); 42 addedge(u,v),addedge(v,u); 43 } 44 dfs(1,-1),mp[F[1]].clear(); 45 scanf("%d",&m); 46 while(m--) { 47 int u; 48 scanf("%d",&u); 49 printf("%d\n",ans[u]); 50 } 51 } 52 return 0; 53 }
线段树合并:(1014ms)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 int n,m,k,a[N],b[N],nb,ans[N],ne,hd[N],ka,tot,rt[N],ls[N*20],rs[N*20],val[N*20],sum[N*20]; 6 #define mid ((l+r)>>1) 7 struct E {int v,nxt;} e[N<<1]; 8 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 9 void pu(int u) {sum[u]=sum[ls[u]]+sum[rs[u]];} 10 int newnode() {int u=++tot; ls[u]=rs[u]=val[u]=sum[u]=0; return u;} 11 void add(int& u,int x,int dx,int l=1,int r=nb) { 12 if(!u)u=newnode(); 13 if(l==r) {val[u]+=dx,sum[u]=val[u]==k; return;} 14 x<=mid?add(ls[u],x,dx,l,mid):add(rs[u],x,dx,mid+1,r); 15 pu(u); 16 } 17 void mg(int& u,int v,int l=1,int r=nb) { 18 if(!u||!v) {u=u|v; return;} 19 if(l==r) {val[u]+=val[v],sum[u]=val[u]==k; return;} 20 mg(ls[u],ls[v],l,mid),mg(rs[u],rs[v],mid+1,r),pu(u); 21 } 22 void dfs(int u,int fa) { 23 rt[u]=0,add(rt[u],a[u],1); 24 for(int i=hd[u]; ~i; i=e[i].nxt) { 25 int v=e[i].v; 26 if(v==fa)continue; 27 dfs(v,u),mg(rt[u],rt[v]); 28 } 29 ans[u]=sum[rt[u]]; 30 } 31 int main() { 32 int T; 33 for(scanf("%d",&T); T--;) { 34 if(ka)puts(""); 35 printf("Case #%d:\n",++ka); 36 memset(hd,-1,sizeof hd),ne=0; 37 memset(ans,0,sizeof ans),tot=0; 38 scanf("%d%d",&n,&k); 39 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 40 for(int i=1; i<=n; ++i)b[i]=a[i]; 41 sort(b+1,b+1+n),nb=unique(b+1,b+1+n)-(b+1); 42 for(int i=1; i<=n; ++i)a[i]=lower_bound(b+1,b+1+nb,a[i])-b; 43 for(int i=1; i<n; ++i) { 44 int u,v; 45 scanf("%d%d",&u,&v); 46 addedge(u,v),addedge(v,u); 47 } 48 dfs(1,-1); 49 scanf("%d",&m); 50 while(m--) { 51 int u; 52 scanf("%d",&u); 53 printf("%d\n",ans[u]); 54 } 55 } 56 return 0; 57 }
还不够爽?再来个资瓷在线查询的可持久化线段树合并怎么样?就是有点吃内存。(1310ms)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 int n,m,k,a[N],b[N],nb,ne,hd[N],ka,tot,rt[N],ls[N*40],rs[N*40],val[N*40],sum[N*40]; 6 #define mid ((l+r)>>1) 7 struct E {int v,nxt;} e[N<<1]; 8 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 9 void pu(int u) {sum[u]=sum[ls[u]]+sum[rs[u]];} 10 int newnode() {int u=++tot; ls[u]=rs[u]=val[u]=sum[u]=0; return u;} 11 void add(int& w,int u,int x,int dx,int l=1,int r=nb) { 12 w=newnode(); 13 if(l==r) {val[w]=val[u]+dx,sum[w]=val[w]==k; return;} 14 if(x<=mid)add(ls[w],ls[u],x,dx,l,mid),rs[w]=rs[u]; 15 else add(rs[w],rs[u],x,dx,mid+1,r),ls[w]=ls[u]; 16 pu(w); 17 } 18 void mg(int& w,int u,int v,int l=1,int r=nb) { 19 if(!u||!v) {w=u|v; return;} 20 w=newnode(); 21 if(l==r) {val[w]=val[u]+val[v],sum[w]=val[w]==k; return;} 22 mg(ls[w],ls[u],ls[v],l,mid),mg(rs[w],rs[u],rs[v],mid+1,r),pu(w); 23 } 24 void dfs(int u,int fa) { 25 rt[u]=0,add(rt[u],rt[u],a[u],1); 26 for(int i=hd[u]; ~i; i=e[i].nxt) { 27 int v=e[i].v; 28 if(v==fa)continue; 29 dfs(v,u),mg(rt[u],rt[u],rt[v]); 30 } 31 } 32 int main() { 33 int T; 34 for(scanf("%d",&T); T--;) { 35 if(ka)puts(""); 36 printf("Case #%d:\n",++ka); 37 memset(hd,-1,sizeof hd),ne=0; 38 tot=0; 39 scanf("%d%d",&n,&k); 40 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 41 for(int i=1; i<=n; ++i)b[i]=a[i]; 42 sort(b+1,b+1+n),nb=unique(b+1,b+1+n)-(b+1); 43 for(int i=1; i<=n; ++i)a[i]=lower_bound(b+1,b+1+nb,a[i])-b; 44 for(int i=1; i<n; ++i) { 45 int u,v; 46 scanf("%d%d",&u,&v); 47 addedge(u,v),addedge(v,u); 48 } 49 dfs(1,-1); 50 scanf("%d",&m); 51 while(m--) { 52 int u; 53 scanf("%d",&u); 54 printf("%d\n",sum[rt[u]]); 55 } 56 } 57 return 0; 58 }