4 1 2 2 1 1 2 2 3 3 4 5 1 1 2 1 2 1 3 2 3 3 5 4 5
1 2 1 1 1 2 1
方法一:线段树合并。
#include"cstdio"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"vector"
using namespace std;
const int maxn = 1e5+5;
const int maxm = 3e6+5;
int n,col[maxn],c[maxn],ans[maxn],r[maxn];
struct edge{
int v,nxt;
}e[maxn<<1];
int alloc,tail,head[maxn];
void init(){
alloc = 0;
tail = -1;
memset(head,-1,sizeof(head));
memset(col,0,sizeof(col));
}
void add(int u, int v)
{
e[++tail] = (edge){v,head[u]}; head[u] = tail;
e[++tail] = (edge){u,head[v]}; head[v] = tail;
}
struct node{
int l,r;
int val,sum;
}tree[maxm];
void pushup(int rt)
{
tree[rt].sum = tree[tree[rt].l].sum + tree[tree[rt].r].sum;
}
int build(int c, int l, int r)
{
int rt = ++alloc;
tree[rt].l = tree[rt].r = 0;
tree[rt].val = tree[rt].sum = 0;
if(l == r){
tree[rt].val = 1;
tree[rt].sum = (tree[rt].val < col[l]);
return rt;
}
int mid = l+r>>1;
if(c <= mid) tree[rt].l = build(c,l,mid);
else tree[rt].r = build(c,mid+1,r);
pushup(rt);
return rt;
}
int merge(int rt1, int rt2, int l, int r)
{
if(!rt1) return rt2;
if(!rt2) return rt1;
if(l == r){
tree[rt1].val += tree[rt2].val;
tree[rt1].sum = (tree[rt1].val < col[l]);
return rt1;
}
int mid = l+r>>1;
tree[rt1].l = merge(tree[rt1].l,tree[rt2].l,l,mid);
tree[rt1].r = merge(tree[rt1].r,tree[rt2].r,mid+1,r);
pushup(rt1);
return rt1;
}
void dfs(int u, int fa, int ed)
{
r[u] = build(c[u],1,n);
for(int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v;
if(v == fa) continue;
dfs(v,u,i);
merge(r[u],r[v],1,n);
}
// cout<
ans[ed/2+1] = tree[r[u]].sum;
}
int main()
{
int u,v;
while(~scanf("%d",&n)){
init();
for(int i = 1; i <= n; i++){
scanf("%d",&c[i]);
col[c[i]]++;
}
for(int i = 1; i < n; i++){
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(1,1,-2);
for(int i = 1; i < n; i++){
printf("%d\n",ans[i]);
}
}
return 0;
}
方法二:dfs序+莫队算法
#include"cmath"
#include"cstdio"
#include"cstring"
#include"iostream"
#include"vector"
#include"algorithm"
using namespace std;
const int maxn = 1e5+7;
int ans[maxn],a[maxn],b[maxn],col[maxn],cnt[maxn],fro[maxn],head[maxn],flag[maxn];
int pos[maxn];
int n,tot,ed,tail;
struct edge{
int to, nxt;
}e[maxn*2];
struct node{
int l, r, id;
node(){}
node(int ll, int rr, int ii):l(ll),r(rr),id(ii){}
}Q[maxn];
void add(int u, int v)
{
e[++ed] = (edge){v,head[u]}; head[u] = ed;
e[++ed] = (edge){u,head[v]}; head[v] = ed;
}
void dfs(int u, int fa, int edg)
{
fro[u] = ++tot;
a[tot] = b[u];
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa) continue;
dfs(v,u,i);
}
Q[++tail] = node(fro[u],tot,(edg+1)/2);
}
bool cmp(node a, node b){
if(pos[a.l] == pos[b.l])
return a.r < b.r;
return pos[a.l] < pos[b.l];
}
void work(int id, int &now)
{
if(cnt[id] > 0 && cnt[id] < col[id]){
if(!flag[id]) now++;
flag[id] = 1;
}
else{
if(flag[id]) now--;
flag[id] = 0;
}
}
int main()
{
int u,v;
while(~scanf("%d",&n)){
int sz = sqrt(n);
tot = ed = tail = 0;
memset(col,0,sizeof(col));
memset(cnt,0,sizeof(cnt));
memset(head,0,sizeof(head));
memset(flag,0,sizeof(flag));
for(int i = 1; i <= n; i++){
int x;
scanf("%d",&x);
b[i] = x;
col[x]++;
pos[i] = i/sz;
}
for(int i = 1; i < n; i++){
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(1,1,0);
sort(Q+1,Q+n,cmp);
int L = 1, R = 0, now = 0;
for(int i = 1; i < n; i++){
while(L < Q[i].l){
L++;
int id = a[L-1];
cnt[id]--;
work(id,now);
}
while(L > Q[i].l){
int id = a[L-1];
cnt[id]++;
L--;
work(id,now);
}
while(R < Q[i].r){
R++;
int id = a[R];
cnt[id]++;
work(id,now);
}
while(R > Q[i].r){
int id = a[R];
cnt[id]--;
R--;
work(id,now);
}
ans[Q[i].id] = now;
}
for(int i = 1; i < n; i++)
printf("%d\n",ans[i]);
}
return 0;
}