【题解】ADAGRAFT - Ada and Graft [SP33331]
传送门:( ext{Ada and Graft}) ( ext{[SP33331]})
【题目描述】
给出一颗 (n) 个节点的树(根为 (0)),树的价值定义为每个节点的价值乘积。每个节点的值是其子树中不同颜色种类的数量。
给出每个节点上的颜色,求树价值。答案对 (10^9+7) 取模。
【输入】
第一行包含一个整数 (n)。
第二行包含 (n-1) 个整数 (p_{i}),分别表示节点 (i) 的父亲节点。
第三行包含 (n) 个整数 (F_{i}),表示节点 (i) 的颜色。
【输出】
输出一个整数表示答案模 (10^9+7) 的值。
【样例】
样例输入1:
5
0 0 1 1
1 1 1 2 2
样例输出1:
4
样例输入2:
4
0 1 2
6 7 2 3
样例输出2:
24
样例输入3
11
0 1 1 1 3 5 2 7 5 4
494052753 959648710 959648710 959648710 494052753 959648710 959648710 959648710 959648710 494052753 959648710
样例输出3
32
【数据范围】
(100\%) (1 leqslant N leqslant 4*10^5,) (1 leqslant F_{i} leqslant 10^9,) (0 leqslant p_{i} leqslant i)
【分析】
求以某个节点为根的子树信息,很明显的线段树合并。
考虑将所有点的权值离散化一下,对每个节点开一颗动态开点权值线段树,按照 (dfs) 的遍历顺序不断合并所有子节点,便可得到所有节点的价值,最后乘起来即可。
合并两个权值线段树时可以直接取 (or),向上传递信息直接 (S[p]=S[pl]+S[pr])。
注意取模!!!
【Code】
#include<algorithm>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=4e5+3,P=1e9+7;
int n,m,x,y,o,Ans=1,A[N],B[N],pt[N],ans[N],head[N];
struct QAQ{int to,next;}a[N<<1];
inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
inline void in(Re &x){
Re fu=0;x=0;char ch=getchar();
while(ch<'0'||ch>'9')fu|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=fu?-x:x;
}
struct Segment_Tree{
#define pl tr[p].lp
#define pr tr[p].rp
#define mid (L+R>>1)
int cnt;
struct QAQ{int S,lp,rp;}tr[N*38];//空间要开够
inline void pushup(Re p){tr[p].S=tr[pl].S+tr[pr].S;}
inline void change(Re &p,Re L,Re R,Re w){
if(!p)p=++cnt;
if(L==R){tr[p].S=1;return;}
if(w<=mid)change(pl,L,mid,w);
else change(pr,mid+1,R,w);
pushup(p);
}
inline int merge(Re p,Re q,Re L,Re R){
if(!p)return q;if(!q)return p;
if(L==R){tr[p].S|=tr[q].S;return p;}//合并信息
pl=merge(pl,tr[q].lp,L,mid);
pr=merge(pr,tr[q].rp,mid+1,R);
pushup(p);return p;
}
}T1;
inline void dfs(Re x,Re fa){
for(Re i=head[x],to;i;i=a[i].next)
if((to=a[i].to)!=fa)
dfs(to,x),pt[x]=T1.merge(pt[x],pt[to],1,m);
ans[x]=T1.tr[pt[x]].S;//直接获取整个大区间的答案
}
int main(){
// freopen("123.txt","r",stdin);
in(n);
for(Re i=2;i<=n;++i)in(x),add(++x,i),add(i,x);
for(Re i=1;i<=n;++i)in(A[i]),B[i]=A[i];
sort(B+1,B+n+1),m=unique(B+1,B+n+1)-B-1;
for(Re i=1;i<=n;++i)T1.change(pt[i],1,m,lower_bound(B+1,B+m+1,A[i])-B);//初始化建树
dfs(1,0);
for(Re i=1;i<=n;++i)Ans=(LL)Ans*ans[i]%P;
printf("%d
",Ans);
}