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

题目链接

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

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

启发式合并1:(748ms)

 1 #include
 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; ii) {
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
 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; ii) {
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版,原理与普通启发式合并相同,轻链合并到重链上,重链中的父结点的贡献直接加进子结点):(1185ms)

 1 #include
 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; ii) {
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 }
View Code

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

 1 #include
 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()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; ii) {
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
 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; ii) {
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
 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; ii) {
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

 

转载于:https://www.cnblogs.com/asdfsag/p/10800982.html

你可能感兴趣的:(HDU - 4358 Boring counting (树上启发式合并/线段树合并))