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\n", query(dfsx[bel[x]], dfsx[bel[x]] + siz[bel[x]] - 1, rt[bel[x]], dfsx[x]));
135     }
136     }
137   return 0;
138 }

原文地址:https://www.cnblogs.com/mrclr/p/9845892.html

时间: 2024-08-18 03:39:42

luogu P3787 冰精冻西瓜的相关文章

【Luogu】P3787冰精冻西瓜(线段树)

题目链接 我脑子怕不是有坑qwqqq 用前缀和思想,dis[i]表示i离根的距离,那么修改操作其实是对x的子树区间加y/dis[x],查询的时候*dis[to]即可. 对付/0错的思路是建森林,然而这个地方我犯蠢了. qwq. #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cctype> #include<cmath>

[洛谷 P3787] 冰精冻西瓜

题目描述 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质,可以将经过它的冷气的寒冷程度放大或缩小,每条西瓜蔓放大/缩小冷气寒冷程度的能力值为Wi,表示冷气经过它后,寒冷程度值x会变为x*wi.每个西瓜也有一个寒冷程度值,炎热的夏日,所有西瓜的寒冷程度值初始都为0. 琪露诺会做出两种动作: ①.对着西瓜i放出寒冷程度为x的冷气.这股冷气顺着西瓜蔓向"西瓜树"的叶

[Luogu 3787] 冰精冻西瓜

Description 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质,可以将经过它的冷气的寒冷程度放大或缩小,每条西瓜蔓放大/缩小冷气寒冷程度的能力值为Wi,表示冷气经过它后,寒冷程度值x会变为x*wi.每个西瓜也有一个寒冷程度值,炎热的夏日,所有西瓜的寒冷程度值初始都为0. 琪露诺会做出两种动作: ①.对着西瓜i放出寒冷程度为x的冷气.这股冷气顺着西瓜蔓向"西瓜树&

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

题目背景 盛夏,冰之妖精琪露诺发现了一大片西瓜地,终于可以吃到美味的冻西瓜啦. 题目描述 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质,可以将经过它的冷气的寒冷程度放大或缩小,每条西瓜蔓放大/缩小冷气寒冷程度的能力值为Wi,表示冷气经过它后,寒冷程度值x会变为x*wi.每个西瓜也有一个寒冷程度值,炎热的夏日,所有西瓜的寒冷程度值初始都为0. 琪露诺会做出两种动作: ①

冰精冻西瓜[P3787洛谷]

题目描述 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质,可以将经过它的冷气的寒冷程度放大或缩小,每条西瓜蔓放大/缩小冷气寒冷程度的能力值为Wi,表示冷气经过它后,寒冷程度值x会变为x*wi.每个西瓜也有一个寒冷程度值,炎热的夏日,所有西瓜的寒冷程度值初始都为0. 琪露诺会做出两种动作: ①.对着西瓜i放出寒冷程度为x的冷气.这股冷气顺着西瓜蔓向"西瓜树"的叶

对于有关东方的题目的整理。。

东方赛高 此为总贴 收录以东方project为背景的题目. 1. luogu P3345 [ZJOI2015]幻想乡战略游戏 动态点分治(暴力水过) 2. luogu P3344 [ZJOI2015]幻想乡WIFI搭建计划 3. luogu P3343 [ZJOI2015]地震后的幻想乡 4. luogu P3346 [ZJOI2015]诸神眷顾的幻想乡 5. luogu P3347 [ZJOI2015]醉熏熏的幻想乡 6. luogu P1726 上白泽慧音 求强连通分量, 输出最大强连通分量

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

题目背景 伊吹萃香(Ibuki Suika)正在魔法之森漫步,突然,许多西瓜(Suika)从四周飞来,划出了绚丽的轨迹.虽然阵势有点恐怖,但她还是决定抱走一些西瓜. 题目描述 萃香所处的环境被简化为一个长为h,宽为w的网格平面.X坐标范围为[1,w],y坐标范围为[1,h]. 她初始(第1个时刻)站在坐标为sx,sy的方格. 西瓜可能在任意一个方格出现,在每个时间单位,它们可能向任何一个方向移动,也可能静止不动.西瓜的位置和移动的轨迹是已知的.西瓜的总数为n个,但只有m个西瓜可以被萃香抱走,因为

luogu P3799 妖梦拼木棒

二次联通门 : luogu P3799 妖梦拼木棒 /* luogu P3799 妖梦拼木棒 用一个桶存下所有的木棒 美剧两根短的木棒长度 后随便乘一乘就 好了.. */ #include <algorithm> #include <cstdio> #define Mod 1000000007 #define Max 5000 void read (int &now) { now = 0; register char word = getchar (); while (wo

[luogu P1967][NOIp2013]P1967 货车运输

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z