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;
}