bzoj2631: tree

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mod 51061
#define maxn 100005
#define ll unsigned int
using namespace std;

int n,q,fa[maxn],son[maxn][2],size[maxn];
bool rev[maxn];
ll val[maxn],lazyc[maxn],lazyh[maxn],sum[maxn];

struct date{
    int which(int x){
        return son[fa[x]][1]==x;
    }
    bool isroot(int x){
        return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
    }
    void update(int x){
        size[x]=size[son[x][0]]+size[son[x][1]]+1;
        sum[x]=val[x]%mod;
        if (son[x][0]) sum[x]=(sum[x]+sum[son[x][0]])%mod;
        if (son[x][1]) sum[x]=(sum[x]+sum[son[x][1]])%mod;
    }
    void jia(int x,ll y){
        lazyh[x]=(lazyh[x]+y)%mod;
        val[x]=(val[x]+y)%mod;
        sum[x]=(sum[x]+size[x]*y%mod)%mod;
    }
    void cheng(int x,ll y){
        if (lazyh[x]){
            lazyh[x]=(lazyh[x]*y)%mod;
        }
        lazyc[x]=(lazyc[x]*y)%mod;
        val[x]=(val[x]*y)%mod;
        sum[x]=(sum[x]*y)%mod;
    }
    void pushdown(int x){
        if (rev[x]){
            rev[x]^=1,swap(son[x][0],son[x][1]);
            if (son[x][0]) rev[son[x][0]]^=1;
            if (son[x][1]) rev[son[x][1]]^=1;
        }
        if (lazyc[x]!=1){
            if (son[x][0]) cheng(son[x][0],lazyc[x]);
            if (son[x][1]) cheng(son[x][1],lazyc[x]);
            lazyc[x]=1;
        }
        if (lazyh[x]){
            if (son[x][0]) jia(son[x][0],lazyh[x]);
            if (son[x][1]) jia(son[x][1],lazyh[x]);
            lazyh[x]=0;
        }
    }
    void relax(int x){
        if (!isroot(x)) relax(fa[x]);
        pushdown(x);
    }
    void rotata(int x){
        int y=fa[x],d=which(x),dd=which(y);
        if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y];
        fa[son[x][d^1]]=y,son[y][d]=son[x][d^1];
        fa[y]=x,son[x][d^1]=y;
        update(y);
    }
    void splay(int x){
        relax(x);
        while (!isroot(x)){
            if (isroot(fa[x])) rotata(x);
            else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x);
            else rotata(x),rotata(x);
        }
        update(x);
    }
    void access(int x){
        for (int p=0;x;x=fa[x]){
            splay(x);
            son[x][1]=p;
            update(x);
            p=x;
        }
    }
    void make_root(int x){
        access(x);
        splay(x);
        rev[x]^=1;
    }
    void link(int x,int y){
        make_root(x),fa[x]=y;
    }
    void cut(int x,int y){
        make_root(x);
        access(y);
        splay(y);
        son[y][0]=fa[x]=0;
        update(y);
    }
    void split(int x,int y){
        make_root(x);
        access(y);
        splay(y);
    }
    void add(int x,int y,ll z){
        split(x,y);
        jia(y,z);
    }
    void multiply(int x,int y,ll z){
        split(x,y);
        cheng(y,z);
    }
    void query(int x,int y){
        split(x,y);
        printf("%u\n",sum[y]%mod);
    }
}lct;

int main(){
//    freopen("tree.in","r",stdin);
//    freopen("tree.out","w",stdout);
    char st[12];
    int u,v,U,V;
    ll UU,VV;
    memset(size,0,sizeof(size));
    memset(fa,0,sizeof(fa));
    memset(son,0,sizeof(son));
    memset(rev,0,sizeof(rev));
    scanf("%d%d",&n,&q);
    for (int i=1;i<=n;i++){
        val[i]=1,sum[i]=1,lazyc[i]=1,lazyh[i]=0,size[i]=1;
    }
    for (int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        lct.link(u,v);
    }
    while (q--){
        scanf("%s%d%d",st+1,&u,&v);
        if (st[1]=='+') scanf("%u",&UU),lct.add(u,v,UU);
        else if (st[1]=='-') scanf("%d%d",&U,&V),lct.cut(u,v),lct.link(U,V);
        else if (st[1]=='*') scanf("%u",&UU),lct.multiply(u,v,UU);
        else lct.query(u,v);
    }
    return 0;
}
View Code

 

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2631

做法:链乘链加:先传乘标记,并且把加标记乘上这个数,再传加标记;

看个变形就很显然了:(ax+b)*c=a*c*x+b*c,显然加标记也要乘上这个数。

posted @ 2016-05-17 21:16  oyzx~  阅读(118)  评论(0编辑  收藏  举报