luogu P3787 冰精冻西瓜

Posted mrclr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3787 冰精冻西瓜相关的知识,希望对你有一定的参考价值。

嘟嘟嘟

 

好题,好题……

看这个修改和询问,就知道要么是求完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
", 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 冰精冻西瓜的主要内容,如果未能解决你的问题,请参考以下文章

冰精冻西瓜[P3787洛谷]

[luogu U8984][新创无际夏日公开赛] 冰精冻西瓜 [树状数组]

luogu P3786 萃香抱西瓜

[luogu P3786]萃香抱西瓜 [spfa][状态压缩]

题解Luogu CF1051F The Shortest Statement

合成大西瓜开发源码,手把手教你运行和部署大西瓜游戏项目