【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>
#define left (rt<<1)
#define right (rt<<1|1)
#define mid ((l+r)>>1)
#define lson l,mid,left
#define rson mid+1,r,right
#define maxn 2000020
#define eps 1e-8
using namespace std;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==‘-‘)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-‘0‘;
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int next,to;
    double val;
}edge[maxn*3];
int head[maxn],num;
inline void add(int from,int to,double val){
    edge[++num]=(Edge){head[from],to,val};
    head[from]=num;
}

double tree[maxn*4];
double tag[maxn*4];
int dfn[maxn];
int root[maxn];
int father[maxn];
int top[maxn];
int son[maxn];
int deep[maxn];
int size[maxn];
double dis[maxn];
int tme,n,m;

void unifnd(int x,int fa){
    if(x==fa){
        dis[x]=1;
        root[x]=x;
    }
    else    root[x]=root[fa];
    deep[x]=deep[fa]+1;    size[x]=1;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(deep[to])    continue;
        if(fabs(edge[i].val)>eps){
            father[to]=x;
            dis[to]=dis[x]*edge[i].val;
            unifnd(to,x);
            size[x]+=size[to];
            if(son[x]==0||size[son[x]]<size[to])    son[x]=to;
        }
        else    unifnd(to,to);
    }
    return;
}

void unionn(int x,int Top){
    dfn[x]=++tme;    top[x]=Top;
    if(son[x]==0)    return;
    unionn(son[x],Top);
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==father[x]||to==son[x])    continue;
        if(edge[i].val==0)    continue;
        unionn(to,to);
    }
}

inline void prepare(){
    unifnd(1,1);
    for(int i=1;i<=n;++i)
        if(dfn[i]==0)    unionn(root[i],root[i]);
}

inline void pushup(int rt){    tree[rt]=tree[left]+tree[right];    }

void pushdown(int rt,int m){
    if(fabs(tag[rt])<=eps)    return;
    tag[left]+=tag[rt];    tag[right]+=tag[rt];
    tree[left]+=tag[rt]*(m-(m>>1));
    tree[right]+=tag[rt]*(m>>1);
    tag[rt]=0;
}

void update(int from,int to,double num,int l,int r,int rt){
    if(from<=l&&to>=r){
        tree[rt]+=num*(r-l+1);
        tag[rt]+=num;
        return;
    }
    pushdown(rt,r-l+1);
    if(from<=mid)    update(from,to,num,lson);
    if(to>mid)        update(from,to,num,rson);
}

double query(int o,int l,int r,int rt){
    if(l==r)    return tree[rt];
    double ans=0;
    pushdown(rt,r-l+1);
    if(o<=mid)    ans+=query(o,lson);
    else        ans+=query(o,rson);
    return ans;
}

void add(int x,double num){
    update(dfn[x],dfn[x]+size[x]-1,num/dis[x],1,n,1);
    return;
}

inline double ask(int x){
    return query(dfn[x],1,n,1)*dis[x];
}

int main(){
    n=read();
    for(int i=1;i<n;++i){
        int x=read(),y=read();
        double z;    scanf("%lf",&z);
        add(x,y,z);
        add(y,x,z);
    }
    prepare();
    m=read();
    for(int i=1;i<=m;++i){
        int opt=read(),x=read();
        if(opt==1){
            double y;    scanf("%lf",&y);
            add(x,y);
        }
        else    printf("%.8lf\n",ask(x));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cellular-automaton/p/8383600.html

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

【Luogu】P3787冰精冻西瓜(线段树)的相关文章

luogu P3787 冰精冻西瓜

嘟嘟嘟 好题,好题-- 看这个修改和询问,就知道要么是求完dfs序后线段树维护,要么是树剖.又因为这道题都是子树的操作,没有链上的,所以线段树就够了. 然而重点不是这个.这道题最麻烦的是线段树pushdown时对于每一个节点打的标记都不一样,因为每一条边上的能力值不一样.这也是这道题最巧妙的一点:我们把每一次对节点 i 放的冷气都转移到从根节点放的,这样pushdown的标记就统一了. 具体操作是啥咧:假如u到跟要经过w1, w2, w3这三条边,那么我们对u放x的冷气,就相当于从根节点放Div

[Luogu 3787] 冰精冻西瓜

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

[洛谷 P3787] 冰精冻西瓜

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

【原创】洛谷 LUOGU P3373 【模板】线段树2

P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x

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

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

冰精冻西瓜[P3787洛谷]

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

luogu P3373 【模板】线段树 2

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x y k 含义:将区间[x,y]内

【Luogu】P2221高速公路(线段树乱搞)

题目链接 这题……我从一开始就想歪了qwq. 为了缅怀逝去的一小时我就把我的30分暴力思路放上来. 首先我们观察枚举的区间.假设我们要枚举的范围是1~5之间的四条路,为了方便我们把它们叫做abcd. 那么观察我们枚举的区间. a ab abc abcd b bc bcd c cd d 观察有一些区间是可以合起来的. 然后观察a出现4次,b出现6次,c出现6次,d出现4次. 是有一定规律的qwq 然后就$\frac{nm}{2}的复杂度搞搞 就三十分 正确思路是,观察一条路选不选上(设这条路左点x

Luogu 3373 - 【模板】线段树 2 - [加乘线段树]

题目链接:https://www.luogu.org/problemnew/show/P3373 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区