【20190125 颜色对】
每对 ( a , b ) (a,b) (a,b)中 ( u , v ) (u,v) (u,v)保证 u u u是 v v v的祖先节点,就先想到了查询 u u u的子树,用上 D F S DFS DFS序,就可以转为区间查询了。
如果在线查,建 r r r颗树状数组,或是每次重新建,或直接暴力,肯定是不可取的,就考虑离线查。
初步考虑对于每一个颜色单独查询。
首先先把节点的颜色,询问的
b
b
b从大到小排序。(每个颜色可以对应查询)
再跑
D
F
S
DFS
DFS序。
按照询问一个一个地查。
如果到了新的颜色,就节点对应的颜色加入树状数组,考虑到不用修改,就把树状数组改成前缀和,查询就从
O
(
l
o
g
n
)
O(logn)
O(logn)到了
O
(
1
)
O(1)
O(1)。
(前缀和
s
[
i
]
s[i]
s[i]表示,
D
F
S
DFS
DFS序前
i
i
i的颜色为
b
b
b的个数)
但每一次查询的时候,都要重新算一下每个颜色为
a
a
a节点的子树和,又是一个
O
(
n
)
O(n)
O(n),所以在每个颜色中预处理,查询就
O
(
1
)
O(1)
O(1)。
至于预处理,就按
D
F
S
DFS
DFS序,从
1
1
1 ~
n
n
n循环一遍,查询子树和,把答案算入该节点颜色作为
a
a
a的贡献里去。
最后按询问的位置排序,输出即可。
#include<bits/stdc++.h>
#include<queue>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+5;
int n,r,q,col[N];
priority_queue< pair<int,int> >p;
struct edge{
int v,nxt;
}e[N];
int first[N],cnt=0;
inline void add(int u,int v){
e[++cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt;
}
struct ques{
int a,b,id,ans;
}a[N<<1];
inline bool SORT(const ques &x,const ques &y){
return x.b>y.b;
}
inline bool Sort(const ques &x,const ques &y){
return x.id<y.id;
}
int pos[N],end[N],tot=0;
void dfs(int x){
pos[x]=++tot;
for(int i=first[x];i;i=e[i].nxt)
dfs(e[i].v);
end[x]=tot;
}
int preans[N],s[N];
int main(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
n=read();r=read();q=read();
col[1]=read();
p.push(make_pair(col[1],1));
for(int i=2;i<=n;i++){
int f;
f=read();col[i]=read();
add(f,i);
p.push(make_pair(col[i],i));
}
for(int i=1;i<=q;i++){
a[i].a=read();a[i].b=read();
a[i].id=i;a[i].ans=0;
}
sort(a+1,a+q+1,SORT);
dfs(1);
int tq=1,last=0;
while(tq<=q){
if(a[tq].b!=last){
if(p.empty())break;
memset(s,0,sizeof(s));
memset(preans,0,sizeof(preans));
while(!p.empty()){
int x=p.top().second;
if(col[x]!=a[tq].b)break;
p.pop();
s[pos[x]]++;
}
last=a[tq].b;
for(int i=1;i<=n;i++)s[i]+=s[i-1];
for(int i=1;i<=n;i++)
preans[col[i]]+=s[end[i]]-s[pos[i]];
}
a[tq].ans=preans[a[tq].a];
tq++;
}
sort(a+1,a+q+1,Sort);
for(int i=1;i<=q;i++)printf("%d\n",a[i].ans);
return 0;
}
复杂度貌似是
O
(
n
r
)
O(nr)
O(nr)的,但不知道就过了。
好像是因为
r
r
r太小了。
所以貌似是个错误算法。
只有当颜色的个数大于根号 n n n,才处理,剩下一次 D F S DFS DFS处理完。