BZOJ 2361 tree(动态树)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2631

题意:一棵n个点的树,每个点的初始权值为1。对于这棵树有以下四种操作:
(1)+ u v c:将u到v的路径上的点的权值都加上自然数c;
(2)- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
(3)* u v c:将u到v的路径上的点的权值都乘上自然数c;
(4)/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

思路:(1)splay(x):将x旋转到所在树链的根;

(2)access(x):将x到树根root之间的边连上,即x与root成为一条树链;

(3)makeroot(x):将x设为树的树根,这个操作也就是将x到树根root之间的边反向即可;

(4)join(x,y):连接x和y之间的边。makeroot(x),然后access(y),splay(y),此时x是所在树链的根,y是所在树链的根,直接将x的父节点设为y即可;

(5)cut(x,y):断开x和y之间的边。makeroot(x),然后access(y),splay(y),此时x是root,y是所在树链的根,且y和root在一个树链上,因此x是y的左孩子,直接断开即可。

(6)对于加法和乘法:设置参数a和b,则整个可表示为a*x+b,若乘,则等价于(a*x+b)*c,若加,则等价于(a*x+b)+c。

 


   
const int mod=51061;
const i64 inf=((i64)1)<<60;
const double dinf=1000000000000000000.0;
const int INF=100000000;
const int N=200005;


struct node
{
    i64 a,x,b,sum;
    int size,isRev;
    node *c[2],*f;
    
    
    void add(i64 bb)
    {
        sum=(sum+size*bb)%mod;
        b=(b+bb)%mod;
        x=(x+bb)%mod;
    }
    void mul(i64 aa)
    {
        sum=sum*aa%mod;
        a=a*aa%mod;
        b=b*aa%mod;
        x=x*aa%mod;
    }
    
    void reverse()
    {
        isRev^=1;
        swap(c[0],c[1]);
    }
};


node a[N],*nullNode;




void init()
{
    nullNode=new node;
    nullNode->a=nullNode->b=nullNode->x=nullNode->sum=0;
    nullNode->size=nullNode->isRev=0;
    nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode;
}




void pushUp(node *x)
{
    if(x==nullNode) return;
    x->size=x->c[0]->size+1+x->c[1]->size;
    x->sum=(x->c[0]->sum+x->x+x->c[1]->sum)%mod;
}




void pushDown(node *x)
{
    if(x==nullNode) return;
    if(x->a!=1)
    {
        if(x->c[0]!=nullNode) x->c[0]->mul(x->a);
        if(x->c[1]!=nullNode) x->c[1]->mul(x->a);
        x->a=1;
    }
    if(x->b!=0)
    {
        if(x->c[0]!=nullNode) x->c[0]->add(x->b);
        if(x->c[1]!=nullNode) x->c[1]->add(x->b);
        x->b=0;
    }
    if(x->isRev)
    {
        if(x->c[0]!=nullNode) x->c[0]->reverse();
        if(x->c[1]!=nullNode) x->c[1]->reverse();
        x->isRev=0;
    }
}


int isRoot(node *x)
{
    if(x->f==nullNode) return 1;
    node *p=x->f;
    return p->c[0]!=x&&p->c[1]!=x;
}


void zig(node *x)
{
    node *p=x->f,*q=p->f;
    p->c[0]=x->c[1];
    if(x->c[1]!=nullNode) x->c[1]->f=p;
    x->c[1]=p;
    p->f=x;
    x->f=q;
    if(q!=nullNode)
    {
        if(q->c[0]==p) q->c[0]=x;
        if(q->c[1]==p) q->c[1]=x;
    }
    pushUp(p);
    pushUp(x);
}


void zag(node *x)
{
    node *p=x->f,*q=p->f;
    p->c[1]=x->c[0];
    if(x->c[0]!=nullNode) x->c[0]->f=p;
    x->c[0]=p;
    p->f=x;
    x->f=q;
    if(q!=nullNode)
    {
        if(q->c[0]==p) q->c[0]=x;
        if(q->c[1]==p) q->c[1]=x;
    }
    pushUp(p);
    pushUp(x);
}


void splay(node *x)
{
    pushDown(x);
    while(!isRoot(x))
    {
        if(!isRoot(x->f))
        {
            pushDown(x->f->f);
            pushDown(x->f);
            pushDown(x);
            if(x->f->f->c[0]==x->f)
            {
                if(x->f->c[0]==x) zig(x->f),zig(x);
                else zag(x),zig(x);
            }
            else 
            {
                if(x->f->c[1]==x) zag(x->f),zag(x);
                else zig(x),zag(x);
            }
        }
        else
        {
            pushDown(x->f);
            pushDown(x);
            if(x->f->c[0]==x) zig(x);
            else zag(x);
        }
    }
}


node *access(node *x)
{
    node *p=nullNode;
    while(x!=nullNode)
    {
        splay(x);
        x->c[1]=p;
        pushUp(x);
        p=x;
        x=x->f;
    }
    return p;
}


void makeRoot(int x)
{
    access(a+x);
    splay(a+x);
    a[x].reverse();
}


void join(int x,int y)
{
    makeRoot(x); access(a+y); splay(a+y);
    a[x].f=a+y;
}


void cut(int x,int y)
{
    makeRoot(x); access(a+y); splay(a+y);
    a[y].c[0]->f=nullNode;
    a[y].c[0]=nullNode;
    splay(a+y);
}


void add(int x,int y,i64 val)
{
    access(a+x);
    node *p=a+y,*q=nullNode;
    while(p!=nullNode)
    {
        splay(p);
        if(p->f==nullNode)
        {
            p->c[1]->add(val);
            q->add(val);
            p->x=(p->x+val)%mod;
        }
        p->c[1]=q;
        q=p;
        pushUp(q);
        p=p->f;
    }
}


void mul(int x,int y,i64 val)
{
    access(a+x);
    node *p=a+y,*q=nullNode;
    while(p!=nullNode)
    {
        splay(p);
        if(p->f==nullNode)
        {
            p->c[1]->mul(val);
            q->mul(val);
            p->x=p->x*val%mod;
        }
        p->c[1]=q;
        q=p;
        pushUp(q);
        p=p->f;
    }
}


i64 getSum(int x,int y)
{
    access(a+x);
    node *p=a+y,*q=nullNode;
    i64 ans=0;
    while(p!=nullNode)
    {
        splay(p);
        if(p->f==nullNode)
        {
            ans+=p->c[1]->sum+q->sum+p->x;
            return ans%mod;
        }
        p->c[1]=q;
        q=p;
        pushUp(q);
        p=p->f;
    }
}


vector<int> g[N];
int n,m;


void build()
{
    queue<int> Q;
    Q.push(1);
    int i,u,v;
    while(!Q.empty())
    {
        u=Q.front();
        Q.pop();
        
        FOR0(i,SZ(g[u]))
        {
            v=g[u][i];
            if(a+v==a[u].f) continue;
            a[v].f=a+u;
            Q.push(v);
        }
    }
}


void go()
{
    char op[10];
    int x,y,x1,y1;
    i64 det;
    while(m--)
    {
        RD(op);
        if(op[0]=='+') RD(x,y),RD(det),add(x,y,det);
        else if(op[0]=='-') RD(x,y),RD(x1,y1),cut(x,y),join(x1,y1);
        else if(op[0]=='*') RD(x,y),RD(det),mul(x,y,det);
        else RD(x,y),PR(getSum(x,y));
    }
}


int main()
{
    init();
    RD(n,m);
    int i,x,y;
    FOR1(i,n-1) RD(x,y),g[x].pb(y),g[y].pb(x);
    FOR1(i,n)
    {
        a[i].a=1; a[i].x=1; a[i].b=0;
        a[i].isRev=0; a[i].size=1;
        a[i].c[0]=a[i].c[1]=a[i].f=nullNode;
    }
    build();
    go();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值