1. 程式人生 > >Boring counting

Boring counting

題目描述戳這裡
題解:
這是典型的樹上查詢和子樹有關資訊並且無修改的題目。
那麼就可以直接DSU on Tree 或者 啟發式合併就好啦。
我寫的是啟發式合併,每次記錄一下當前點的當前列舉過的兒子的顏色集合,那麼當前列舉兒子k,我們只要兩個集合合併一下即可。但是要保證把小的併到大的,這樣就能保證複雜度在O(nlog(n))的範圍內啦。

程式碼如下:

#include<cstdio>
#include<cstring>
#include<string>
#include<map>
using namespace std;
const
int maxn=100005; int T,n,m,ti,Q,tot,ans[maxn],lnk[maxn],son[2*maxn],nxt[2*maxn],siz[maxn],sum[maxn],cnt[maxn],col[maxn]; map <int,int> hsh[maxn]; void add(int x,int y){ son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot; } void dfs1(int x,int fa){ siz[x]=1; for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa) { dfs1(son[j],x); siz[x]+=siz[son[j]]; } } void
merge(int x,int y){ sum[y]+=sum[x]; map<int,int>::iterator it; for (it=hsh[x].begin();it!=hsh[x].end();it++){ if (hsh[y][it->first]==m) cnt[y]--; hsh[y][it->first]+=(it->second); if (hsh[y][it->first]==m) cnt[y]++; } hsh[x].clear(); } int
dfs(int x,int fa){ int wson=x; sum[x]=1; hsh[wson][col[x]]++; if (hsh[wson][col[x]]==m) cnt[wson]++; for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa){ int p=dfs(son[j],x); if (sum[p]>sum[wson]) {merge(wson,p); wson=p;} else merge(p,wson); } ans[x]=cnt[wson]; return wson; } void clear(){ tot=0; memset(lnk,0,sizeof(lnk)); memset(nxt,0,sizeof(nxt)); memset(sum,0,sizeof(sum)); memset(cnt,0,sizeof(cnt)); } int main(){ scanf("%d",&T); while (T--) { clear(); scanf("%d %d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&col[i]); for (int i=1;i<n;i++) { int x,y; scanf("%d %d",&x,&y); add(x,y); add(y,x); } printf("Case #%d:\n",++ti); dfs1(1,0); int x=dfs(1,0); hsh[x].clear(); scanf("%d",&Q); while (Q--) { int x; scanf("%d",&x); printf("%d\n",ans[x]); } if (T) printf("\n"); } return 0; }