• 【题解】ADAGRAFT


    【题解】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);
    }
    
  • 相关阅读:
    前端开发神器
    React表单明文密文切换,携带禁止浏览器自动回填,简单验证提示功能
    webapp 虚拟键盘隐藏留下空白解决办法
    jQuery常用表单事件执行顺序
    localStorage+cookie实现存取表单历史记录
    js.cookie.js使用方法
    H5超细边框
    JS删除数组中某个元素
    JS获取地址栏参数(支持中文)
    React书写规范
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11837311.html
Copyright © 2020-2023  润新知