傳送門
 
題意:
 
 思路: 很明顯子樹問題會想到樹啟,讓后如何updateupdateupdate呢?一個顯然的思路就是維護一個樹狀數組,查詢次數>=kj>=k_j>=kj?的個數。但是這樣復雜度是O(nlog2n)O(nlog^2n)O(nlog2n)的,有沒有更優的方式呢?注意到我們可以維護一個出現次數的前綴和,記數組cnt[i]cnt[i]cnt[i]為出現次數為iii的顏色個數,c[i]c[i]c[i]為iii顏色出現的次數,當前顏色為colcolcol。每次更新的時候,比如說現在tagtagtag為111,按正常的思路應該是c[col]++,cnt[c[col]?1]??,cnt[c[col]]++c[col]++,cnt[c[col]-1]--,cnt[c[col]]++c[col]++,cnt[c[col]?1]??,cnt[c[col]]++。這樣寫的話,就需要用樹狀數組查詢一下>=k>=k>=k的個數了,但是我們修改一下cnt[i]cnt[i]cnt[i]的含義,改成出現次數>=i>=i>=i的顏色個數(我語文不好,別打臉),這樣修改的時候只需要c[col]++,cnt[c[col]]++c[col]++,cnt[c[col]]++c[col]++,cnt[c[col]]++,這樣更新的時候答案就是cnt[k]cnt[k]cnt[k]了。
 復雜度O(nlogn)O(nlogn)O(nlogn)。
 如果改成出現次數<kj<k_j<kj?的顏色個數,我們只需要再維護一下子樹中顏色的個數sumsumsum,那么ans=sum?cnt[kj]ans=sum-cnt[k_j]ans=sum?cnt[kj?]。
 
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
;
int col
[N
],se
[N
],son
[N
];
int cnt
[N
],c
[N
],ans
[N
];
vector
<int>v
[N
];
vector
<PII
>query
[N
];void dfs_son(int u
,int f
)
{se
[u
]=1;for(auto x
:v
[u
]) if(x
!=f
) { dfs_son(x
,u
); se
[u
]+=se
[x
]; if(se
[x
]>se
[son
[u
]]) son
[u
]=x
; }
}void update(int u
,int f
,int tag
,int p
)
{if(tag
==1) c
[col
[u
]]++,cnt
[c
[col
[u
]]]++;else c
[col
[u
]]--,cnt
[c
[col
[u
]]+1]--;for(auto x
:v
[u
]) if(x
!=f
&&x
!=p
) update(x
,u
,tag
,p
);
}void dfs(int u
,int f
,int op
)
{for(auto x
:v
[u
]) if(x
!=f
&&x
!=son
[u
]) dfs(x
,u
,0);if(son
[u
]) dfs(son
[u
],u
,1);update(u
,f
,1,son
[u
]);for(int i
=0;i
<query
[u
].size();i
++) ans
[query
[u
][i
].X
]=cnt
[query
[u
][i
].Y
];if(!op
) update(u
,f
,-1,0);
}int main()
{
scanf("%d%d",&n
,&m
);for(int i
=1;i
<=n
;i
++) scanf("%d",&col
[i
]);for(int i
=1;i
<=n
-1;i
++){int a
,b
; scanf("%d%d",&a
,&b
);v
[a
].pb(b
); v
[b
].pb(a
);}for(int i
=1;i
<=m
;i
++){int v
,k
; scanf("%d%d",&v
,&k
);query
[v
].pb({i
,k
});}dfs_son(1,0); dfs(1,0,0);for(int i
=1;i
<=m
;i
++) printf("%d\n",ans
[i
]);return 0;
}
                            總結
                            
                                以上是生活随笔為你收集整理的CodeForces - 375D  Tree and Queries  树启 + 思维的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。