您的位置:首页 > 产品设计 > UI/UE

codeforces 375D Tree and Queries

2016-07-07 07:22 585 查看
题目链接

题目大意

给定一棵树,n个节点,m个询问。

每次询问以vi为根的子树中,点数大于等于ki的颜色个数。

题解

对于这种询问子树的问题,经常会转到序列上。毕竟,序列较树有着无比优越性。

比如说,莫队算法。

利用dfs序将树转到序列上后,就可以套用莫队算法了。

维护区间时需要维护每种颜色的个数cnti,同时要维护颜色大于等于i的颜色个数sumi。

每次删除一个数,就把这种颜色的cnt减一,由于只有这种颜色变化了,所以sum变化的只有原来的cntcoli,所以在减一之前,先把sumcntcoli减一。

当加入一个数时,先把这个颜色的cnt加一,然后,sumcntcoli也要加一。

#include<cstdio>
#include<vector>
#include<cassert>
#include<cmath>
#include<cctype>
#include<set>
#include<algorithm>
using namespace std;
const int M=100005;
int col[M],L[M],R[M],dfs_clock,s;
int ans[M],cnt[M],sum[M],tmp[M];
vector<int>edge[M];
struct Query{
int L,R,num,id;
}q[M];
inline void rd(int&res){
res=0;char c;
while(c=getchar(),!isdigit(c));
do res=res*10+(c^48);
while(c=getchar(),isdigit(c));
}
void rec(int x,int f){
L[x]=++dfs_clock;
for(int i=0;i<edge[x].size();i++)
if(edge[x][i]!=f) rec(edge[x][i],x);
R[x]=dfs_clock;
}
bool cmp(Query a,Query b){
if(a.L/s==b.L/s) return a.R<b.R;
return a.L/s<b.L/s;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
s=(int)sqrt(n);
for(int i=1;i<=n;i++)
rd(col[i]);
for(int i=1;i<n;i++){
int a,b;
rd(a);rd(b);
edge[a].push_back(b);
edge[b].push_back(a);
}
rec(1,0);
for(int i=0;i<m;i++){
int a,b;
rd(a);rd(b);
q[i]=(Query){L[a],R[a],b,i};
}
for(int i=1;i<=n;i++)
tmp[i]=col[i];
for(int i=1;i<=n;i++)
col[L[i]]=tmp[i];
sort(q,q+m,cmp);
int L=0,R=0,res=0;
for(int i=0;i<m;i++){
while(R<q[i].R){
R++;
cnt[col[R]]++;
sum[cnt[col[R]]]++;
}
while(L>q[i].L){
L--;
cnt[col[L]]++;
sum[cnt[col[L]]]++;
}
while(L<q[i].L){
sum[cnt[col[L]]]--;
cnt[col[L]]--;
L++;
}
while(R>q[i].R){
sum[cnt[col[R]]]--;
cnt[col[R]]--;
R--;
}
ans[q[i].id]=sum[q[i].num];
}
for(int i=0;i<m;i++)
printf("%d\n",ans[i]);
return 0;
}


遗留问题

这题还可以用map的启发式合并来写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces 莫队 dfs序