[loj6208]树上询问——线段树 大佬们的博客 Some Links

题目大意:

有一棵 n 节点的树,根为 1 号节点。每个节点有两个权值 k i , t i ​​,初始值均为 0
给出三种操作:
A d d ( x , d ) 操作:将 x 到根的路径上所有点的 k i k i + d
M u l ( x , d ) 操作:将 x 到根的路径上所有点的 t i t i + d × k i
Q u e r y ( x ) 操作:询问点 x 的权值 t x

思路:

线段树好题。
首先把树上的操作通过树链剖分就转变为了序列上面的操作了。然后考虑怎么在序列上面维护每一个点的答案。
由于修改是区间修改,所以在线段树上的操作不可以及时更新,需要打标记,并且一个标记暂时是独立表示一个状态的,因此我们的标记要满足可以与之前的点快速合并。
将操作转化一下以便于理解,1操作可以看不断地增加一个矩形某条边的高,2操作可以看成在前面所有的高的基础下矩形的宽又增加 d 个单位。
这样以后对于两个不同的已知状态的矩形,就可以通过记录每个矩形目前的高和宽以及通过操作得到的面积快速pushdown了。具体操作看pushdown里面的代码会便于理解。

/*========================
Author : ylsoi
Problem : loj6208
Algorithm : Segment Tree
Time : 2018.8.1
========================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("loj6208.in","r",stdin);
    freopen("loj6208.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=1e5+10;
int n,m;
int cnte=1,beg[maxn],las[maxn<<1],to[maxn<<1];
int dep[maxn],son[maxn],fa[maxn],siz[maxn],top[maxn],dfn[maxn],cnt_dfn;

void add(int u,int v){
    las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
    las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u;
}

void dfs1(int u,int f){
    dep[u]=dep[f]+1; fa[u]=f; siz[u]=1;
    for(int i=beg[u];i;i=las[i]){
        if(to[i]==f)continue;
        dfs1(to[i],u);
        siz[u]+=siz[to[i]];
        if(siz[to[i]]>siz[son[u]])
            son[u]=to[i];
    }
}

void dfs2(int u,int t){
    top[u]=t; dfn[u]=++cnt_dfn;
    if(son[u])dfs2(son[u],t);
    for(int i=beg[u];i;i=las[i]){
        if(to[i]==son[u] || to[i]==fa[u])continue;
        dfs2(to[i],to[i]);
    }
}

struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
    ll a[maxn<<2],b[maxn<<2],c[maxn<<2];
    void pushdown(int rt){
        c[lc]=c[lc]+c[rt]+a[lc]*b[rt]; a[lc]+=a[rt]; b[lc]+=b[rt];
        c[rc]=c[rc]+c[rt]+a[rc]*b[rt]; a[rc]+=a[rt]; b[rc]+=b[rt];
        c[rt]=a[rt]=b[rt]=0;
    }
    void update(int rt,int l,int r,int L,int R,bool ty,ll x){
        if(L<=l && r<=R){
            if(ty==0)a[rt]+=x;
            else b[rt]+=x,c[rt]+=a[rt]*x;
        }
        else{
            pushdown(rt);
            if(L<=mid)update(lson,L,R,ty,x);
            if(R>=mid+1)update(rson,L,R,ty,x);
        }
    }
    ll query(int rt,int l,int r,int pos){
        if(l==r)return c[rt];
        pushdown(rt);
        if(pos<=mid)return query(lson,pos);
        else return query(rson,pos);
    }
}T;

void modify(bool ty,int u,ll x){
    while(u){
        T.update(1,1,n,dfn[top[u]],dfn[u],ty,x);
        u=fa[top[u]];
    }
}

int main(){
    File();
    read(n);
    int ty,u,v;
    REP(i,1,n-1)read(u),read(v),add(u,v);
    dfs1(1,0); dfs2(1,1);
    read(m);
    REP(i,1,m){
        read(ty);
        if(ty==1 || ty==2){
            read(u); read(v);
            modify(ty-1,u,v);
        }
        else{
            read(u);
            printf("%lld\n",T.query(1,1,n,dfn[u]));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81357203