1. 程式人生 > >luogu P3787 冰精凍西瓜

luogu P3787 冰精凍西瓜

dig string last 統一 ons push eof lse head

嘟嘟嘟

好題,好題……

看這個修改和詢問,就知道要麽是求完dfs序後線段樹維護,要麽是樹剖。又因為這道題都是子樹的操作,沒有鏈上的,所以線段樹就夠了。

然而重點不是這個。這道題最麻煩的是線段樹pushdown時對於每一個節點打的標記都不一樣,因為每一條邊上的能力值不一樣。這也是這道題最巧妙的一點:我們把每一次對節點 i 放的冷氣都轉移到從根節點放的,這樣pushdown的標記就統一了。

具體操作是啥咧:假如u到跟要經過w1, w2, w3這三條邊,那麽我們對u放x的冷氣,就相當於從根節點放Div[u] = w1 * w2 * w3 * x的冷氣,查詢v的冷氣值的時候把線段樹得到的答案除以Div[v]即可。預處理Div[i]dfs一遍即可。

然而這道題還沒完,因為Div[i]可以等於0,所以這棵樹實際上會斷成一個森林。所以就有好多個根節點,以及好多棵線段樹,但是空間大小是不變的。

所以要記錄每一棵樹的根節點,再從根節點開始dfs,維護的Div[i]實際上表示的是 i 到他所在的樹的根節點的Πwi。(一定是從根節點開始!我就是因為從樹中任意一棵節點開始導致85分,今天聽bin哥講完後突然才想出來這個問題)

技術分享圖片
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5
#include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16
typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-9; 20 const int maxn = 1e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - 0; ch = getchar();} 27 if(last == -) ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar(-); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + 0); 35 } 36 37 int n, m; 38 struct Edge 39 { 40 int nxt, to; 41 db w; 42 }e[maxn << 1]; 43 int head[maxn], ecnt = -1; 44 void addEdge(int x, int y, db w) 45 { 46 e[++ecnt] = (Edge){head[x], y, w}; 47 head[x] = ecnt; 48 } 49 50 int st[maxn], top = 0; 51 bool vis[maxn]; 52 int rt[maxn], bel[maxn]; 53 int siz[maxn], dfsx[maxn], pos[maxn], cnt = 0; 54 db Div[maxn]; 55 bool zero(db x) 56 { 57 return x >= -eps && x <= eps; 58 } 59 void dfs(int now, int id) 60 { 61 vis[now] = 1; siz[now] = 1; bel[now] = id; 62 dfsx[now] = ++cnt; pos[cnt] = now; 63 for(int i = head[now]; i != -1; i = e[i].nxt) 64 { 65 if(vis[e[i].to]) continue; 66 if(zero(e[i].w)) st[++top] = e[i].to; 67 else 68 { 69 Div[e[i].to] = Div[now] * e[i].w; 70 dfs(e[i].to, id); 71 siz[now] += siz[e[i].to]; 72 } 73 } 74 } 75 76 int ls[maxn << 2], rs[maxn << 2], ctr = 0; 77 db sum[maxn << 2], lzy[maxn << 2]; 78 void pushdown(int now) 79 { 80 if(!zero(lzy[now])) 81 { 82 if(!ls[now]) ls[now] = ++ctr; 83 if(!rs[now]) rs[now] = ++ctr; 84 sum[ls[now]] += lzy[now]; sum[rs[now]] += lzy[now]; 85 lzy[ls[now]] += lzy[now]; lzy[rs[now]] += lzy[now]; 86 lzy[now] = 0; 87 } 88 } 89 void update(int l, int r, int L, int R, int& now, db d) 90 { 91 if(!now) now = ++ctr; 92 if(l == L && r == R) {sum[now] += d; lzy[now] += d; return;} 93 pushdown(now); 94 int mid = (l + r) >> 1; 95 if(R <= mid) update(l, mid, L, R, ls[now], d); 96 else if(L > mid) update(mid + 1, r, L, R, rs[now], d); 97 else update(l, mid, L, mid, ls[now], d), update(mid + 1, r, mid + 1, R, rs[now], d); 98 } 99 db query(int l, int r, int& now, int id) 100 { 101 if(!now) now = ++ctr; 102 if(l == r) return sum[now] * Div[pos[id]]; 103 pushdown(now); 104 int mid = (l + r) >> 1; 105 if(id <= mid) return query(l, mid, ls[now], id); 106 else return query(mid + 1, r, rs[now], id); 107 } 108 109 int main() 110 { 111 Mem(head, -1); 112 n = read(); 113 for(int i = 1; i < n; ++i) 114 { 115 int x = read(), y = read(); 116 db w; scanf("%lf", &w); 117 addEdge(x, y, w); addEdge(y, x, w); 118 } 119 Div[1] = 1.00; dfs(1, 1); 120 for(int i = 1; i <= top; ++i) Div[st[i]] = 1.00, dfs(st[i], st[i]); 121 m = read(); 122 for(int i = 1; i <= m; ++i) 123 { 124 int d = read(); 125 if(d == 1) 126 { 127 int x = read(); 128 db w; scanf("%lf", &w); 129 update(dfsx[bel[x]], dfsx[bel[x]] + siz[bel[x]] - 1, dfsx[x], dfsx[x] + siz[x] - 1, rt[bel[x]], w / Div[x]); 130 } 131 else 132 { 133 int x = read(); 134 printf("%.8lf\n", query(dfsx[bel[x]], dfsx[bel[x]] + siz[bel[x]] - 1, rt[bel[x]], dfsx[x])); 135 } 136 } 137 return 0; 138 }
View Code

luogu P3787 冰精凍西瓜