• 【PKUWC2018】Minimax


    Link: Luogu https://www.luogu.com.cn/problem/P5298 or LibreOJ https://loj.ac/problem/2537


    Solution


    这个要查询的东西看起来没有什么意义啊、、
    先看一下数据范围,应该是要 (O(nlog n)) 时间的。

    本题的树高并非 (O(log n)) 不过其实对复杂度没什么影响、

    题目保证了每个结点的子结点数不超过 2 。那么稍微思考一下马上就可以发现
    这是不是可以直接模拟啊?后序遍历一下?
    考虑对于某个结点维护它的值为多少多少的概率,一路从下往上合并?
    那么很明显在转移的时候需要分别对左边和右边的每个值
    乘上另一边转移过来的概率,再乘上一个另一边转移之前的概率和(是个前/后缀和)

    不妨设结点 (i) 值为 (j) 的概率为 (p_{i,j}),那么应当这样转移:(记左右子树为 (l,r) 且离散化后最大权值为 (v)

    [p_{i,j}=p_{l,j}left[(1-p_x)sumlimits_{s=1}^{j-1}p_{r,s}+p_xsumlimits_{s=j+1}^{v}p_{r,s} ight]+p_{r,j}left[(1-p_x)sumlimits_{s=1}^{j-1}p_{l,s}+p_xsumlimits_{s=j+1}^{v}p_{l,s} ight] ]

    ?怎么做这个
    看起来很复杂。

    其实非常简单啊,等号左边跟等号右边完全独立
    那随便写写就可以了,,lazytag用来带好多好多的plj prj
    然后sum是向叶子递归的时候一路带下去的,
    就是普通权值线段树那种算前后缀和。

    顺便记得逆元。

    日常制杖time:①今天我写权值线段树没有排序就上了
    ②并且在用到之前把两个变量递归下去给改飞了(有两个递归应该大概没问题吧
    ③最后统计结果没有Pushdown


    Code


    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    const int MAXN = 3e5 + 10;
    const int SEGN = MAXN << 5;
    const int MOD = 998244353;
    int n, SurLc[MAXN], SurRc[MAXN];
    int val[MAXN], FormVal[MAXN];
    int valtot = 0;
    int Root[MAXN];
    int SegLc[SEGN], SegRc[SEGN], SegTot = 0;
    long long seg_mul_tag[SEGN], seg_prb_value[SEGN];
    long long qpowm(long long a, long long b)
    {
        long long Ans = 1;
        while (b)
        {
            if (b & 1)
            {
                Ans = Ans * a % MOD;
            }
            a = a * a % MOD;
            b >>= 1;
        }
        return Ans;
    }
    
    void Insert(int &Pos, int L, int R, int Value)
    {
        Pos = ++SegTot;
        seg_prb_value[Pos] = seg_mul_tag[Pos] = 1;
        if (L < R)
        {
            int Mid = L + R >> 1;
            if (Value <= Mid) Insert(SegLc[Pos], L, Mid, Value);
            else Insert(SegRc[Pos], Mid + 1, R, Value);
        }
    }
    
    void update(int pos, long long mul)
    {
    	if (!pos) return;
        seg_mul_tag[pos] = seg_mul_tag[pos] * mul % MOD;
        seg_prb_value[pos] = seg_prb_value[pos] * mul % MOD;
        return;
    }
    
    void pushdown(int pos)
    {
        if (!pos || seg_mul_tag[pos]==1) return;
        if (SegLc[pos]) update(SegLc[pos], seg_mul_tag[pos]);
        if (SegRc[pos]) update(SegRc[pos], seg_mul_tag[pos]);
        seg_mul_tag[pos] = 1;
    }
    
    int MMmerge(int x, int y, long long xSum, long long ySum, long long pr)
    {
        if (!x && !y) return 0;
        if (!x)
        {
            update(y, xSum);
            return y;
        }
        if (!y)
        {
            update(x, ySum);
            return x;
        }
        pushdown(x);
        pushdown(y);
        long long Temptemp = seg_prb_value[SegLc[x]], Temptemptemp = seg_prb_value[SegLc[y]];
        long long orz = seg_prb_value[SegRc[x]], orzorz = seg_prb_value[SegRc[y]];
    	SegLc[x] = MMmerge(SegLc[x], SegLc[y], ((1ll-pr+MOD)%MOD*orz%MOD+xSum)%MOD, ((1ll-pr+MOD)%MOD*orzorz%MOD+ySum)%MOD, pr);
        SegRc[x] = MMmerge(SegRc[x], SegRc[y], (1ll*pr*Temptemp%MOD+xSum) % MOD, (1ll*pr*Temptemptemp%MOD+ySum) % MOD, pr);
        seg_prb_value[x] = (seg_prb_value[SegLc[x]] + seg_prb_value[SegRc[x]])%MOD;
        return x;
    }
    
    void Initialize(int Position)
    {
        if (!SurLc[Position])
        {
            Insert(Root[Position], 1, valtot, val[Position]);
            return;
        }
    
        if (SurRc[Position])
        {
        	Initialize(SurLc[Position]);
            Initialize(SurRc[Position]);
            Root[Position] = MMmerge(Root[SurLc[Position]], Root[SurRc[Position]], 0, 0, val[Position]);
        }
        else
        {
        	Initialize(SurLc[Position]);
        	Root[Position] = Root[SurLc[Position]];
        }
    
    }
    
    long long Ans = 0;
    
    void Calculate(int pos, int l, int r)
    {
        if (!pos) return;
        if (l == r)
        {
            Ans = (Ans + 1ll * l * FormVal[l] % MOD * seg_prb_value[pos] % MOD * seg_prb_value[pos] % MOD) % MOD;
            return;
        }
        pushdown(pos);
    	int mid = l + r >> 1;
        Calculate(SegLc[pos], l, mid);
        Calculate(SegRc[pos], mid + 1, r);
    }
    
    int main()
    {
        cin >> n;
        for (int fa, i = 1; i <= n; ++i)
        {
            cin >> fa;
            if (i==1) continue;
            if (!SurLc[fa]) SurLc[fa] = i;
            else SurRc[fa] = i;
        }
        for (int i = 1; i <= n; ++i)
        {
            cin >> val[i];
            if (!SurLc[i])
            {
                FormVal[++valtot] = val[i];
            }
            else
            {
                val[i] = 1ll * val[i] * qpowm(10000, MOD - 2) % MOD;
            }
        }
        sort(FormVal + 1, FormVal + 1 + valtot);
        valtot = unique(FormVal + 1, FormVal + 1 + valtot) - FormVal - 1;
        for (int i = 1; i <= n; ++i)
        {
        	if (!SurLc[i])
        	{
        		val[i] = lower_bound(FormVal + 1, FormVal + 1 + valtot, val[i]) - FormVal;
        	}
        }
        Initialize(1);
        Calculate(Root[1], 1, valtot);
        cout << Ans;
        return 0;
    }
    
  • 相关阅读:
    3D流水线
    log4cplus 配置文件的编写
    linux下的log4cplus的安装和使用
    日志信息的编写与调用
    转C++内存池实现
    转:自定义内存池的使用
    在linux查看内存的大小
    转:C++内存池
    数组指针 和指针数组的区别
    new的三种形态
  • 原文地址:https://www.cnblogs.com/ccryolitecc/p/13775368.html
Copyright © 2020-2023  润新知