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

Posted asdfsag

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 4358 Boring counting (树上启发式合并/线段树合并)相关的知识,希望对你有一定的参考价值。

题目链接

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

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

启发式合并1:(748ms)

技术图片
 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 }
View Code

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

技术图片
 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 }
View Code

启发式合并3(map版):(1263ms)

技术图片
 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 }
View Code

线段树合并:(1014ms)

技术图片
 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 }
View Code

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

技术图片
 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 }
View Code

 

以上是关于HDU - 4358 Boring counting (树上启发式合并/线段树合并)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5056 Boring count(数学)

[HDU]3518——Boring counting

hdu3518 Boring counting

HDU3518 Boring counting

Boring Class HDU - 5324 (CDQ分治)

HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)