1. 程式人生 > >[Luogu 3787] 冰精凍西瓜

[Luogu 3787] 冰精凍西瓜

等等 double dfs http 發現 數量 def fin 如果

Description

琪露諾是擁有操縱冷氣程度的能力的妖精,一天她發現了一片西瓜地。這裏有n個西瓜,由n-1條西瓜蔓連接,形成一個有根樹,琪露諾想要把它們冷凍起來慢慢吃。

這些西瓜蔓具有神奇的性質,可以將經過它的冷氣的寒冷程度放大或縮小,每條西瓜蔓放大/縮小冷氣寒冷程度的能力值為Wi,表示冷氣經過它後,寒冷程度值x會變為x*wi。每個西瓜也有一個寒冷程度值,炎熱的夏日,所有西瓜的寒冷程度值初始都為0。

琪露諾會做出兩種動作:

①.對著西瓜i放出寒冷程度為x的冷氣。這股冷氣順著西瓜蔓向“西瓜樹”的葉子節點蔓延,冷氣的寒冷程度會按照上面的規則變化。遇到一個西瓜連了多條西瓜蔓時,每條葉子節點方向的西瓜蔓均會獲得與原先寒冷程度相等的冷氣。途徑的所有西瓜的寒冷程度值都會加上冷氣的寒冷程度值。

⑨.向你詢問西瓜i的寒冷程度值是多少。

等等,為什麽會有⑨?因為笨蛋琪露諾自己也會忘記放了多少冰呢。

所以,幫她計算的任務就這麽交給你啦。

Input

第一行一個整數n,表示西瓜的數量。

西瓜編號為1~n,1為這棵“西瓜樹”的根。

接下來n-1行,每行有兩個整數u,v和一個實數w,表示西瓜u和西瓜v之間連接有一條藤蔓,它放大/縮小冷氣寒冷程度的能力值為w。

接下來一行一個整數m,表示操作的數量。

接下來m行,每行兩個或三個整數。

第一個數只能是1或9。

如果為1,接下來一個整數i和一個實數x,表示對西瓜i放出寒冷程度為x的冷氣。

如果為9,接下來一個整數i,表示詢問編號為i的西瓜的寒冷程度值。

Output

對於每個操作⑨,輸出一行一個實數,表示對應西瓜的寒冷程度值。

Hint

技術分享圖片

Solution

對於那些邊權為0的邊,顯然只有從這條邊下面出發的冷氣才能對這棵子樹有貢獻。所以不妨將所有邊權為0的邊看作不存在的邊,將這棵樹劃分成幾個內部邊權都不為0的聯通塊,易證,每個聯通塊都是一棵樹。

然後dfs一遍求出每棵樹內每個點到根節點的邊權之積,也就是說,求出如果有一個寒冷程度為1的冷氣從根節點出發, 到達每個節點的寒冷程度貢獻要求出來為 dis。

然後就可以線段樹做了。

ps:因為dis是從根節點出發到當前這個點的乘積,所以修改的時候要用讀入的y除以當前的dis才是真正要改的值。

編輯器換了字體心情都好起來了

Code

#include<cstdio>
#include<cctype>
#include<vector>
#define N 100005
#define db double
#define min(A,B) ((A)<(B)?(A):(B))
#define max(A,B) ((A)>(B)?(A):(B))
#define swap(A,B) ((A)^=(B)^=(A)^=(B))

db dis[N];
int n,cnt,m;
db ch[N<<2];
std::vector<int> son;
int dfn[N],tot,sze[N];
db sum[N<<2],lazy[N<<2];
int head[N],vis[N],fs[N];

struct Edge{
    int to,nxt;
    db dis;
}edge[N<<1];

void add(int x,int y,db z){
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    edge[cnt].dis=z;
    head[x]=cnt;
}

int getint(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch)) f|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return x;
}

void dfs2(int now){
    sze[now]=1;dfn[now]=++tot;fs[tot]=now;
    for(int i=head[now];i;i=edge[i].nxt){
        int to=edge[i].to;
        if(sze[to]) continue;
        if(edge[i].dis==0){
            son.push_back(to);
            continue;
        }
        dis[to]=edge[i].dis*dis[now];
        dfs2(to);
        sze[now]+=sze[to];
    }
}

void build(int cur,int l,int r){
    if(l==r){
        ch[cur]=dis[fs[l]];
        return;
    }
    int mid=l+r>>1;
    build(cur<<1,l,mid);
    build(cur<<1|1,mid+1,r);
    ch[cur]=ch[cur<<1]+ch[cur<<1|1];
}

void pushdown(int cur){
    if(lazy[cur]==0) return;
    sum[cur<<1]+=lazy[cur]*ch[cur<<1];
    sum[cur<<1|1]+=lazy[cur]*ch[cur<<1|1];
    lazy[cur<<1]+=lazy[cur];
    lazy[cur<<1|1]+=lazy[cur];
    lazy[cur]=0;
}

void modify(int cur,int l,int r,int ql,int qr,db c){
    if(ql<=l and r<=qr){
        sum[cur]+=c*ch[cur];
        lazy[cur]+=c;
        return;
    }
    int mid=l+r>>1;
    pushdown(cur);
    if(ql<=mid)
        modify(cur<<1,l,mid,ql,qr,c);
    if(mid<qr)
        modify(cur<<1|1,mid+1,r,ql,qr,c);
    sum[cur]=sum[cur<<1]+sum[cur<<1|1];
}

db query(int cur,int l,int r,int ql,int qr){
    if(ql<=l and r<=qr)
        return sum[cur];
    pushdown(cur);
    int mid=l+r>>1;
    if(ql<=mid)
        return query(cur<<1,l,mid,ql,qr);
    else
        return query(cur<<1|1,mid+1,r,ql,qr);
}

signed main(){
    n=getint();
    for(int i=1;i<n;i++){
        int x=getint(),y=getint();
        db z;scanf("%lf",&z);
        add(x,y,z);add(y,x,z);
    }
    son.push_back(1);
    for(int i=0;i<son.size();i++)
        dis[son[i]]=1.0,dfs2(son[i]);
    build(1,1,n);
    m=getint();
    while(m--){
        if(getint()==1){
            int x=getint();
            db y;scanf("%lf",&y);
            modify(1,1,n,dfn[x],dfn[x]+sze[x]-1,y/dis[x]);
        } else{
            int x=getint();
            printf("%.8lf\n",query(1,1,n,dfn[x],dfn[x]));
        }
    }
    return 0;
}

[Luogu 3787] 冰精凍西瓜