题意:有一行$n(n \leq 100000)$个方格,从左往右第$i$个方格的值为$p_i(p_i = \frac{a}{b}, 1 \leq a < b \leq 1e9)$,有两种操作,一种是将某个方格的值更新为另一个分数表示的有理数,另一种操作是寻味区间$[l, r](l \leq r)$的权值$w(l, r)$;$w(l, r)$如下定义:
方格在位置$i$有$p_i$的概率向右移动一格,有$1-p_i$的概率向左移动一格。$w(l, r)$表示方格初始位置在$l$并且以在位置$r$向右移动(下一个位置为$r+1$)为终结,移动过程始终不超出区间范围的概率值。
分析:对于任一区间$[l, r]$,设$f(i)$表示目前在位置$i$,在移动合法的情况下到达终结状态的概率值。那么显然有$f(i) = p_if(i + 1) + (1 - p_i)f(i - 1)$,注意边界情况是$f(l - 1) = 0$, 且$f(r + 1) = 1$,我们设$w(l, r) = f(l) = \Delta$,那么可以得到递推关系$f(r + 1) = 1 = g(r + 1) + f(r - 1)$,其中$g(r + 1) = \frac{\prod_{i \leq r - 1}(1 - p_i)}{\prod_{i \leq r}p_i} $,理论上我们可以用$g(i)$前缀和得到任意区间的和,用线段树分别维护奇数位置和偶数位置即可。然而,由于$g(i)$可能会非常大,以至于double存储失效,因此此方法并不可行。
用分类统计的方法来解,考虑小规模问题与大规模问题之间的联系,$[l, r]$中间一任意位置为$m$,讨论方格穿过$m$的次数(等比求和),于是可以得到具有局部可累加性质的递推关系。用线段上进行点维护和区间查询即可。单次询问复杂度$O(log(n))$。
code:
1 #include <algorithm> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <queue> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <ctime> 10 #include <cmath> 11 #include <iostream> 12 #include <assert.h> 13 #pragma comment(linker, "/STACK:102400000,102400000") 14 #define max(a, b) ((a) > (b) ? (a) : (b)) 15 #define min(a, b) ((a) < (b) ? (a) : (b)) 16 #define mp std :: make_pair 17 #define st first 18 #define nd second 19 #define keyn (root->ch[1]->ch[0]) 20 #define lson (u << 1) 21 #define rson (u << 1 | 1) 22 #define pii std :: pair<int, int> 23 #define pll pair<ll, ll> 24 #define pb push_back 25 #define type(x) __typeof(x.begin()) 26 #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++) 27 #define FOR(i, s, t) for(int i = (s); i <= (t); i++) 28 #define ROF(i, t, s) for(int i = (t); i >= (s); i--) 29 #define dbg(x) std::cout << x << std::endl 30 #define dbg2(x, y) std::cout << x << " " << y << std::endl 31 #define clr(x, i) memset(x, (i), sizeof(x)) 32 #define maximize(x, y) x = max((x), (y)) 33 #define minimize(x, y) x = min((x), (y)) 34 using namespace std; 35 typedef long long ll; 36 const int int_inf = 0x3f3f3f3f; 37 const ll ll_inf = 0x3f3f3f3f3f3f3f3f; 38 const int INT_INF = (int)((1ll << 31) - 1); 39 const double double_inf = 1e30; 40 const double eps = 1e-14; 41 typedef unsigned long long ul; 42 typedef unsigned int ui; 43 inline int readint() { 44 int x; 45 scanf("%d", &x); 46 return x; 47 } 48 inline int readstr(char *s) { 49 scanf("%s", s); 50 return strlen(s); 51 } 52 53 class cmpt { 54 public: 55 bool operator () (const int &x, const int &y) const { 56 return x > y; 57 } 58 }; 59 60 int Rand(int x, int o) { 61 //if o set, return [1, x], else return [0, x - 1] 62 if (!x) return 0; 63 int tem = (int)((double)rand() / RAND_MAX * x) % x; 64 return o ? tem + 1 : tem; 65 } 66 ll ll_rand(ll x, int o) { 67 if (!x) return 0; 68 ll tem = (ll)((double)rand() / RAND_MAX * x) % x; 69 return o ? tem + 1 : tem; 70 } 71 72 void data_gen() { 73 srand(time(0)); 74 freopen("in.txt", "w", stdout); 75 int kases = 1; 76 //printf("%d\n", kases); 77 while (kases--) { 78 ll sz = 1000; 79 printf("%d %d\n", sz, sz); 80 FOR(i, 1, sz) { 81 int x = Rand(1e2, 1); 82 int y = Rand(1e9, 1); 83 if (x > y) swap(x, y); 84 printf("%d %d\n", x, y); 85 } 86 FOR(i, 1, sz) { 87 int o = Rand(2, 0); 88 if (o) { 89 printf("1 "); 90 int pos = Rand(1000, 1); 91 int x = Rand(1e9, 1), y = Rand(1e9, 1); 92 if (x > y) swap(x, y); 93 printf("%d %d %d\n", pos, x, y); 94 } else { 95 printf("2 "); 96 int x = Rand(1000, 1), y = Rand(1e3, 1); 97 if (x > y) swap(x, y); 98 printf("%d %d\n", x, y); 99 } 100 } 101 } 102 } 103 104 const int maxn = 1e5 + 10; 105 struct Seg { 106 double l1, l2, r1, r2; 107 }seg[maxn << 2]; 108 int n, q; 109 pii a[maxn]; 110 111 void push_up(int u) { 112 seg[u].l2 = seg[lson].l2 * seg[rson].l2 / (1 - seg[lson].r1 * seg[rson].l1); 113 seg[u].l1 = seg[lson].l1 + seg[lson].l2 * seg[lson].r2 * seg[rson].l1 / (1 - seg[lson].r1 * seg[rson].l1); 114 seg[u].r1 = seg[rson].r1 + seg[rson].r2 * seg[rson].l2 * seg[lson].r1 / (1 - seg[lson].r1 * seg[rson].l1); 115 seg[u].r2 = seg[lson].r2 * seg[rson].r2 / (1 - seg[lson].r1 * seg[rson].l1); 116 } 117 118 double query1(int u, int l, int r, int L, int R); 119 double query3(int u, int l, int r, int L, int R); 120 double query4(int u, int l, int r, int L, int R); 121 122 double query(int u, int l, int r, int L, int R) { 123 if (l == L && R == r) return seg[u].l2; 124 int mid = (l + r) >> 1; 125 if (R <= mid) return query(lson, l, mid, L, R); 126 else if (L >= mid) return query(rson, mid, r, L, R); 127 double lhs = query(lson, l, mid, L, mid), rhs = query(rson, mid, r, mid, R); 128 double L1 = query1(rson, mid, r, mid, R), R1 = query3(lson, l, mid, L, mid); 129 return lhs * rhs / (1. - L1 * R1); 130 } 131 132 double query3(int u, int l, int r, int L, int R) { 133 if (l == L && r == R) return seg[u].r1; 134 int mid = (l + r) >> 1; 135 if (R <= mid) return query3(lson, l, mid, L, R); 136 else if (L >= mid) return query3(rson, mid, r, L, R); 137 double tem = query3(rson, mid, r, mid, R); 138 double R2 = query4(rson, mid, r, mid, R); 139 double R1 = query3(lson, l, mid, L, mid); 140 double L2 = query(rson, mid, r, mid, R); 141 double L1 = query1(rson, mid, r, mid, R); 142 return tem + R2 * R1 * L2 / (1. - L1 * R1); 143 } 144 145 double query4(int u, int l, int r, int L, int R) { 146 if (l == L && r == R) return seg[u].r2; 147 int mid = (l + r) >> 1; 148 if (R <= mid) return query4(lson, l, mid, L, R); 149 else if (L >= mid) return query4(rson, mid, r, L, R); 150 double lhs = query4(lson, l, mid, L, mid) * query4(rson, mid, r, mid, R); 151 double rhs = query3(lson, l, mid, L, mid) * query3(rson, mid, r, mid, R); 152 return lhs / (1. - rhs); 153 } 154 155 double query1(int u, int l, int r, int L, int R) { 156 if (l == L && R == r) return seg[u].l1; 157 int mid = (l + r) >> 1; 158 if (R <= mid) return query1(lson, l, mid, L, R); 159 else if (L >= mid) return query1(rson, mid, r, L, R); 160 double tem = query1(lson, l, mid, L, mid); 161 double L1 = query1(rson, mid, r, mid, R); 162 double L2 = query(lson, l, mid, L, mid); 163 double R2 = query4(lson, l, mid, L, mid); 164 double R1 = query3(lson, l, mid, L, mid); 165 return tem + L2 * L1 * R2 / (1. - R1 * L1); 166 } 167 168 void build(int u, int l, int r) { 169 if (r - l < 2) { 170 double p = (double)a[l].first / a[l].nd; 171 seg[u].l1 = 1 - p; 172 seg[u].l2 = p; 173 seg[u].r1 = p; 174 seg[u].r2 = 1 - p; 175 return; 176 } 177 int mid = (l + r) >> 1; 178 build(lson, l, mid), build(rson, mid, r); 179 push_up(u); 180 } 181 182 void update(int u, int l, int r, int L, int R, int lhs, int rhs) { 183 if (l == L && r == R) { 184 double p = (double)lhs / rhs; 185 seg[u].l1 = 1 - p; 186 seg[u].l2 = p; 187 seg[u].r1 = p; 188 seg[u].r2 = 1 - p; 189 return; 190 } 191 int mid = (l + r) >> 1; 192 if (R <= mid) update(lson, l, mid, L, R, lhs, rhs); 193 else update(rson, mid, r, L, R, lhs, rhs); 194 push_up(u); 195 } 196 197 double __get(int x, int y) { 198 return query(1, 1, n + 1, x, y + 1); 199 } 200 201 void __set(int x, int y, int z) { 202 update(1, 1, n + 1, x, x + 1, y, z); 203 } 204 205 int main() { 206 //data_gen(); return 0; 207 //C(); return 0; 208 int debug = 0; 209 if (debug) freopen("in.txt", "r", stdin); 210 //freopen("out.txt", "w", stdout); 211 while (~scanf("%d%d", &n, &q)) { 212 FOR(i, 1, n) scanf("%d%d", &a[i].first, &a[i].nd); 213 build(1, 1, n + 1); 214 FOR(i, 1, q) { 215 int op, x, y, z; 216 scanf("%d%d%d", &op, &x, &y); 217 if (op == 1) { 218 z = readint(); 219 __set(x, y, z); 220 } else { 221 double ans = __get(x, y); 222 printf("%.10f\n", ans); 223 } 224 } 225 } 226 return 0; 227 }