首先是关于这道题的扯淡:早上闲来无事开始orz 2015年的集训队论文,然后发现里面有讲这题……然后就照着邹逍遥神犇讲的分块方法写写写,结果写完交上去发现MLE了,尼玛128MB n根号n内存根本过不了啊,到UOJ群里问了一发被claris等人告知要离线把空间降下来……,这论文题目不是叫《浅谈分块在一类在线问题中的应用》么,怎么还离线了……真是2333
然后是题解:
首先我们按论文里的方法把整个树分块:
设块的大小为S,那么把所有满足深度模S等于0并且子树大小大于等于S的点设为关键点,把所有关键点做一个虚树,虚树的大小还是O(S)的,虚树上的点都叫做关键点
然后我们把答案分成两部分,一部分是x与y之间没有关键点,另一部分是x与y之间有关键点
对于第一部分:
对于任意一个点,他往上走不超过2S步就会遇到一个关键点,那么所有之间没有关键点的点对就有O(nS)个,我们把询问离线,按照较深的点的颜色排序,对于每一个颜色,我们暴力算出以这个颜色的点为较深的点,且两个点之间没有关键点的所有颜色的答案,然后更新所有以这个颜色为较深点的询问的答案
对于第二部分:
对于每个关键点x,我们预处理出x到他在虚树上的父亲之间的路径上的所有点中,每种颜色各有多少个,以及往上走遇到的第一个关键点是x的点中,每种颜色各有多少个,然后对于一个询问,dfs虚树并用预处理的东西算算,就可以得到这个询问的第二部分的答案
有关这种方法具体的各种性质和应用去看论文吧
取S为根号n,我们就可以在O(n sqrt n)的时间内解决此题
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 200010
#define MAXM 25010
#define MAXS 510
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct vec{
int to;
int fro;
};
struct G{
vec mp[MAXN];
int tai[MAXN],cnt;
inline void be(int x,int y);
void pre1(int x,int d);
void pre2(int x,int z);
void dfs(int x,int X,int Y,int I);
};
struct que{
int x;
int y;
int num;
friend bool operator <(que x,que y){
return x.y<y.y;
}
};
que q[MAXN];
G g1,g2;
vec mp[MAXN];
int tai[MAXN],cnt;
int n,m,Q;
int fa[MAXN];
int siz[MAXN];
int S;
bool key[MAXN];
int now;
int vis[MAXN];
int c[MAXN];
int tot;
ll v[MAXM];
vector<int>wh[MAXM];
int c1[MAXS][MAXM],c2[MAXS][MAXM];
int dfn[MAXN];
int TOT;
ll ans[MAXN];
int V;
int q1[MAXN],q2[MAXN];
int T;
vector<int>cs[MAXM];
inline void G::be(int x,int y){
mp[++cnt].to=y;
mp[cnt].fro=tai[x];
tai[x]=cnt;
}
void G::pre1(int x,int d){
int i,y;
siz[x]=1;
int lca=now;
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
pre1(y,d+1);
siz[x]+=siz[y];
}
if(siz[x]>=S&&!(d%S)){
vis[x]=1;
key[x]=key[lca]=1;
}
if(vis[x]){
vis[fa[x]]=1;
now=fa[x];
}
}
void G::pre2(int x,int z){
int i,y;
if(key[x]){
dfn[x]=++TOT;
if(x!=1){
g2.be(z,x);
}
}
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
pre2(y,key[x]?x:z);
}
}
void G::dfs(int x,int X,int Y,int I){
int i,y;
if(c[x]==Y){
ans[I]+=V;
}
V+=c1[dfn[x]][X];
ans[I]+=(ll)V*c2[dfn[x]][Y];
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
dfs(y,X,Y,I);
}
V-=c1[dfn[x]][X];
}
int main(){
int i,j,x,y;
scanf("%d%d%d",&n,&m,&Q);
S=(int)ceil(sqrt(n));
scanf("%d",&c[1]);
cs[c[1]].push_back(1);
for(i=2;i<=n;i++){
scanf("%d%d",&fa[i],&c[i]);
cs[c[i]].push_back(i);
g1.be(fa[i],i);
}
for(i=1;i<=Q;i++){
scanf("%d%d",&q[i].x,&q[i].y);
q[i].num=i;
}
sort(q+1,q+Q+1);
g1.pre1(1,0);
g1.pre2(1,0);
int wzh=1;
for(i=1;i<=m;i++){
T++;
for(j=0;j<cs[i].size();j++){
x=cs[i][j];
y=fa[x];
while(y&&!key[y]){
if(vis[c[y]]!=T){
v[c[y]]=0;
}
vis[c[y]]=T;
v[c[y]]++;
y=fa[y];
}
}
while(wzh<=Q&&q[wzh].y==i){
if(vis[q[wzh].x]!=T){
v[q[wzh].x]=0;
}
ans[q[wzh].num]+=v[q[wzh].x];
wzh++;
}
}
for(i=1;i<=n;i++){
if(key[i]){
x=i;
while(x&&(!key[x]||x==i)){
c1[dfn[i]][c[x]]++;
x=fa[x];
}
}else{
x=i;
while(!key[x]){
x=fa[x];
}
c2[dfn[x]][c[i]]++;
}
}
for(i=1;i<=Q;i++){
V=0;
g2.dfs(1,q[i].x,q[i].y,q[i].num);
}
for(i=1;i<=Q;i++){
printf("%lld\n",ans[i]);
}
return 0;
}
/*
6 3 4
1
1 2
1 3
2 3
2 3
5 1
1 2
1 3
2 3
3 1
*/