传送门
解析:
暴力很好想,我们将所有询问离线,用线性表标注在儿子的颜色上,然后跑 d f s dfs dfs,记录当前节点到根的所有颜色出现的次数,然后就可以统计了。
但是这样会被卡成 O ( n 2 ) O(n^2) O(n2)。。。试想如果一个点的颜色对应很多的询问,那么这些询问难道都需要被回答一次?当然你可以对询问优化,但是没什么用啊。。。要卡的话还是能够卡成 O ( n 2 ) O(n^2) O(n2)。
思路:考虑分类讨论
真正卡住我们的是什么?
当一个颜色的点有很多的时候,所有关于这个颜色的询问都会被回答。
于是就咕咕咕了。
考虑当一个颜色的点多到一定程度,我们就单独处理一次所有与这个颜色有关的询问。
显然,如果只考虑当前颜色的话,我们是能够在 O ( n ) O(n) O(n)时间通过 d f s dfs dfs处理出每个点子树内部和到根的路径上当前颜色的节点的数量。
然后我们在 d f s dfs dfs的时候顺便统计,就可以做到 O ( n ) O(n) O(n)回答所有与颜色 c o l col col有关的询问。
我们设置这个界为 n \sqrt n n,这样就会有不超过 O ( n ) O(\sqrt n) O(n)种颜色需要统计,这部分的复杂度就是 O ( n n ) O(n\sqrt n) O(nn)。
剩下的所有颜色都只有不超过 O ( n ) O(\sqrt n) O(n)个点,所以可以直接来一遍 O ( n ) O(n) O(n)dfs的同时统计答案,这部分复杂度也是 O ( n n ) O(n\sqrt n) O(nn)
代码(严格 O ( n n ) O(n\sqrt n) O(nn)):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=100005,B=200005;
int n,r,q;
vector<int> edge[N];
inline void addedge(int u,int v){
edge[u].push_back(v);
}
int fa[N],siz[N],id[N],dfs_clock;
int tim[N];
void dfs(int u){
id[++dfs_clock]=u;
for(int re e=0;e<edge[u].size();++e)dfs(edge[u][e]);
}
int col[N],cnt[N];
int ans1[N],ans2[N];
inline void calc(int c){
memset(ans1,0,sizeof ans1);
memset(ans2,0,sizeof ans2);
memset(siz,0,sizeof siz);
for(int re i=1;i<=n;++i){
int u=id[i];
siz[u]=siz[fa[u]];
ans1[col[u]]+=siz[u];
if(col[u]==c)++siz[u];
}
memset(siz,0,sizeof siz);
for(int re i=n;i;--i){
int u=id[i];
for(int re e=0;e<edge[u].size();++e)siz[u]+=siz[edge[u][e]];
ans2[col[u]]+=siz[u];
if(col[u]==c)++siz[u];
}
}
int qa[B],qb[B],ans[B];
bool sol[B];
vector<pair<int,int> > qu[N];
inline void dfs_solve(int u){
vector<pair<int,int> > &vec=qu[col[u]];
for(int re i=0;i<vec.size();++i)ans[vec[i].second]+=cnt[vec[i].first];
++cnt[col[u]];
for(int re e=0;e<edge[u].size();++e)dfs_solve(edge[u][e]);
--cnt[col[u]];
}
inline void solve(){
for(int re i=1;i<=q;++i)if(!sol[i])qu[qb[i]].push_back(make_pair(qa[i],i));
memset(cnt,0,sizeof cnt);
dfs_solve(1);
}
signed main(){
n=getint(),r=getint(),q=getint();
++cnt[col[1]=getint()];
for(int re i=2;i<=n;++i){
addedge(fa[i]=getint(),i);
++cnt[col[i]=getint()];
}
dfs(1);
for(int re i=1;i<=q;++i)++tim[qa[i]=getint()],++tim[qb[i]=getint()];
for(int re i=1,lim=sqrt(n);i<=r;++i){
if(cnt[i]>=lim&&tim[i]){
calc(i);
for(int re j=1;j<=q;++j)
if(!sol[j])if(qa[j]==i)sol[j]=true,ans[j]=ans1[qb[j]];
else if(qb[j]==i)sol[j]=true,ans[j]=ans2[qa[j]];
}
}
solve();
for(int re i=1;i<=q;++i)cout<<ans[i]<<"\n";
return 0;
}
代码(乱搞):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<18|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=100005,Q=200005;
int n,r,q;
vector<pair<int,int> > qu[N];
ll ans[Q];
int f[Q];
inline int getfa(int x){
while(x^f[x])x=f[x]=f[f[x]];
return x;
}
int last[N],nxt[N],to[N],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
}
int col[N],b[N];
int cnt[N];
void dfs(cs int &u){
vector<pair<int,int> > &vec=qu[col[u]];
for(int re i=0;i<vec.size();++i)ans[vec[i].second]+=cnt[vec[i].first];
++cnt[col[u]];
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
dfs(v);
--cnt[col[u]];
}
signed main(){
n=getint();r=getint();q=getint();
col[1]=b[1]=getint();
for(int re i=2;i<=n;++i){
addedge(getint(),i);
col[i]=b[i]=getint();
}
sort(b+1,b+n+1);
r=unique(b+1,b+n+1)-b-1;
for(int re i=1;i<=n;++i)col[i]=lower_bound(b+1,b+r+1,col[i])-b;
for(int re i=1;i<=q;++i){
f[i]=i;
int u=getint(),v=getint();
int posu=lower_bound(b+1,b+r+1,u)-b,posv=lower_bound(b+1,b+r+1,v)-b;
if(posu>r||posv>r||b[posu]!=u||b[posv]!=v)continue;
qu[posv].push_back(make_pair(posu,i));
}
for(int re i=1;i<=r;++i){
if(qu[i].size()<=1)continue;
sort(qu[i].begin(),qu[i].end());
vector<pair<int,int> > &vec=qu[i];
int j=0,p=1;
for(;p<vec.size();++p){
if(vec[p].first!=vec[p-1].first)vec[++j]=vec[p];
else f[vec[p].second]=vec[j].second;
}
vec.erase(vec.begin()+j+1,vec.end());
}
dfs(1);
for(int re i=1;i<=q;++i)cout<<ans[getfa(i)]<<"\n";
return 0;
}