LOJ2537 PKUWC2018 Minimax 树形DP、线段树合并
题意:自己去看
首先可以知道,每一个点都有几率被选到,所以$i$与$V_i$的关系是确定了的。
所以我们只需要考虑每一个值的取到的概率。
很容易设计出一个$DP$:设$f_{i,j}$为在第$i$个点取到权值第$j$小的点的概率,转移就是$f_{i,j}=f_{lson,j} \times (\sum \limits _{k<i} f_{rson,k} \times p_x + \sum \limits _{k > i} f_{rson,k} \times (1 - p_x))$($lson$和$rson$之间可以交换),显然是可以前缀和优化的
当然前缀和优化也不够,$O(n^2)$只能过$40pts$。考虑优化。发现在合并的时候$lson$与$rson$之间的元素是互不冲突的,所以可以考虑线段树合并,每一次合并的时候把两边的贡献记录下来,在线段树上打标记即可。
1 #include<bits/stdc++.h> 2 #define ld long double 3 #define int long long 4 #define mid ((l + r) >> 1) 5 #define lch Tree[now].ch[0] 6 #define rch Tree[now].ch[1] 7 //This code is written by Itst 8 using namespace std; 9 10 inline int read(){ 11 int a = 0; 12 bool f = 0; 13 char c = getchar(); 14 while(c != EOF && !isdigit(c)){ 15 if(c == '-') 16 f = 1; 17 c = getchar(); 18 } 19 while(c != EOF && isdigit(c)){ 20 a = (a << 3) + (a << 1) + (c ^ '0'); 21 c = getchar(); 22 } 23 return f ? -a : a; 24 } 25 26 const int MAXN = 300010 , MOD = 998244353; 27 struct node{ 28 int mark , sum , ch[2]; 29 }Tree[MAXN * 20]; 30 int pri[MAXN] , root[MAXN] , lsh[MAXN] , ch[MAXN][2] , cnt , N , cntNode , ny; 31 32 inline void pushup(int now){ 33 Tree[now].sum = (Tree[lch].sum + Tree[rch].sum) % MOD; 34 } 35 36 inline void pushdown(int now){ 37 if(Tree[now].mark != 1){ 38 Tree[lch].sum = Tree[lch].sum * Tree[now].mark % MOD; 39 Tree[rch].sum = Tree[rch].sum * Tree[now].mark % MOD; 40 Tree[lch].mark = Tree[lch].mark * Tree[now].mark % MOD; 41 Tree[rch].mark = Tree[rch].mark * Tree[now].mark % MOD; 42 Tree[now].mark = 1; 43 } 44 } 45 46 void insert(int& now , int l , int r , int tar){ 47 if(!now){ 48 now = ++cntNode; 49 Tree[now].mark = 1; 50 } 51 if(l == r){ 52 Tree[now].sum = 1; 53 return; 54 } 55 pushdown(now); 56 if(mid >= tar) 57 insert(lch , l , mid , tar); 58 else 59 insert(rch , mid + 1 , r , tar); 60 pushup(now); 61 } 62 63 int mer(int p , int q , int markp , int markq , int pri){ 64 if(!(p + q)) 65 return 0; 66 if(!p){ 67 Tree[q].mark = Tree[q].mark * markq % MOD; 68 Tree[q].sum = Tree[q].sum * markq % MOD; 69 return q; 70 } 71 if(!q){ 72 Tree[p].mark = Tree[p].mark * markp % MOD; 73 Tree[p].sum = Tree[p].sum * markp % MOD; 74 return p; 75 } 76 pushdown(p); 77 pushdown(q); 78 int m1 = Tree[Tree[q].ch[1]].sum , n1 = Tree[Tree[p].ch[1]].sum , m2 = Tree[Tree[q].ch[0]].sum , n2 = Tree[Tree[p].ch[0]].sum; 79 Tree[p].ch[0] = mer(Tree[p].ch[0] , Tree[q].ch[0] , (markp + m1 * (10000 - pri) % MOD * ny) % MOD , (markq + n1 * (10000 - pri) % MOD * ny) % MOD , pri); 80 Tree[p].ch[1] = mer(Tree[p].ch[1] , Tree[q].ch[1] , (markp + m2 * pri % MOD * ny) % MOD , (markq + n2 * pri % MOD * ny) % MOD , pri); 81 pushup(p); 82 return p; 83 } 84 85 int getAns(int now , int l , int r){ 86 if(l == r) 87 return l * lsh[l] % MOD * Tree[now].sum % MOD * Tree[now].sum % MOD; 88 else{ 89 pushdown(now); 90 return (getAns(lch , l , mid) + getAns(rch , mid + 1 , r)) % MOD; 91 } 92 } 93 94 void dfs(int now){ 95 if(!ch[now][0]) 96 insert(root[now] , 1 , cnt , pri[now]); 97 else 98 if(!ch[now][1]){ 99 dfs(ch[now][0]); 100 root[now] = root[ch[now][0]]; 101 } 102 else{ 103 dfs(ch[now][0]); 104 dfs(ch[now][1]); 105 root[now] = mer(root[ch[now][0]] , root[ch[now][1]] , 0 , 0 , pri[now]); 106 } 107 } 108 109 inline int poww(long long a , int b){ 110 int times = 1; 111 while(b){ 112 if(b & 1) 113 times = times * a % MOD; 114 a = a * a % MOD; 115 b >>= 1; 116 } 117 return times; 118 } 119 120 signed main(){ 121 #ifndef ONLINE_JUDGE 122 freopen("2537.in" , "r" , stdin); 123 //freopen("2537.out" , "w" , stdout); 124 #endif 125 N = read(); 126 for(int i = 1 ; i <= N ; ++i){ 127 int a = read(); 128 if(!ch[a][0]) 129 ch[a][0] = i; 130 else 131 ch[a][1] = i; 132 } 133 ny = poww(10000 , MOD - 2); 134 for(int i = 1 ; i <= N ; ++i){ 135 pri[i] = read(); 136 if(!ch[i][0]) 137 lsh[++cnt] = pri[i]; 138 } 139 sort(lsh + 1 , lsh + cnt + 1); 140 for(int i = 1 ; i <= N ; ++i) 141 if(!ch[i][0]) 142 pri[i] = lower_bound(lsh + 1 , lsh + cnt + 1 , pri[i]) - lsh; 143 dfs(1); 144 cout << getAns(root[1] , 1 , cnt); 145 return 0; 146 }