2012中国国家集训队命题答辩tree(伍一鸣)

Description:

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

   
   
   

Solution:

    LCT 直接上, Splay 维护每一条链的和,然后记录一个 add,mult 来作为标记。
   
   
   

Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
int N,Q;
const long long Mod=51061;
struct tree_
{
    int fa1;
    int fa2;
    int son[2];
    long long sum;
    long long add;
    long long mult;
    int rev;
    long long Size;
}tree[100010]={{0,0,{0},0,0,0,0,0}};
struct bian_
{
    int to;
    int next;
}bian[200010]={{0,0}};
int First[100010]={0};
void Add(int p,int q,int k)
{
    bian[k].to=q;
    bian[k].next=First[p];
    First[p]=k;
    return;
}
void dfs(int cnt,int fa)
{
    tree[cnt].sum=tree[cnt].Size=1;
    for(int i=First[cnt];i!=0;i=bian[i].next)
    {
        if(bian[i].to==fa) continue;
        tree[bian[i].to].fa2=cnt;
        dfs(bian[i].to,cnt);
    }
    return;
}
void rotate(int k)
{
    int Fa=tree[k].fa1;
    if(tree[Fa].fa1==0)
        swap(tree[Fa].fa2,tree[k].fa2);
    int g=(tree[Fa].son[1]==k);
    swap(tree[k].Size,tree[Fa].Size);
    tree[Fa].Size+=tree[tree[Fa].son[g^1]].Size-tree[tree[k].son[g]].Size;
    int SS=tree[Fa].sum;
    tree[Fa].sum-=tree[k].sum-tree[tree[k].son[g^1]].sum;
    tree[Fa].sum=(tree[Fa].sum+Mod)%Mod;
    tree[k].sum=SS;
    tree[Fa].son[g]=tree[k].son[g^1];
    if(tree[k].son[g^1]!=0)
        tree[tree[k].son[g^1]].fa1=Fa;
    tree[k].son[g^1]=Fa;
    tree[k].fa1=tree[Fa].fa1;
    if(tree[Fa].fa1!=0)
    {
        int gg=(tree[tree[Fa].fa1].son[1]==Fa);
        tree[tree[Fa].fa1].son[gg]=k;
    }
    tree[Fa].fa1=k;
    return;
}
void update(int k)
{
    if(tree[k].fa1!=0)
        update(tree[k].fa1);
    for(int i=0;i<=1;i++)
    {
        if(tree[k].son[i]!=0)
        {
            int child=tree[k].son[i];
            tree[child].rev^=tree[k].rev;
            tree[child].sum=(tree[child].sum*(tree[k].mult+1)+tree[k].add*tree[child].Size)%Mod;
            tree[child].add=(tree[child].add*(tree[k].mult+1)+tree[k].add)%Mod;
            tree[child].mult=((tree[child].mult+1)*(tree[k].mult+1)-1)%Mod;
            if(tree[k].rev&1)
                swap(tree[child].son[0],tree[child].son[1]);
        }
    }
    tree[k].rev=tree[k].add=tree[k].mult=0;
    return;
}
void Splay(int k)
{
    update(k);
    for(;tree[k].fa1!=0;)
    {
        int Fa=tree[k].fa1;
        if(tree[Fa].fa1==0)
            rotate(k);
        else
        {
            int g1=(tree[Fa].son[1]==k),g2=(tree[tree[Fa].fa1].son[1]==Fa);
            if(g1==g2)
                rotate(Fa),rotate(k);
            else rotate(k),rotate(k);
        }
    }
    return;
}
void cut(int k,int g)
{
    int child=tree[k].son[g];
    swap(tree[child].fa1,tree[child].fa2);
    tree[k].sum=(tree[k].sum-tree[child].sum+Mod)%Mod;
    tree[k].Size-=tree[child].Size;
    tree[k].son[g]=0;
    return;
}
void access(int k)
{
    Splay(k);
    if(tree[k].son[1]!=0)
        cut(k,1);
    for(;;)
    {   
        if(tree[k].fa2==0)
            break;
        int O=tree[k].fa2;
        Splay(O);
        if(tree[O].son[1]!=0)
            cut(O,1);
        tree[O].Size+=tree[k].Size;
        tree[O].sum=(tree[O].sum+tree[k].sum)%Mod;
        tree[O].son[1]=k;
        swap(tree[k].fa1,tree[k].fa2);
        Splay(k);
    }
    return;
}
int main()
{
    scanf("%d%d",&N,&Q);
    for(int i=1;i<N;i++)
    {
        int p,q;
        scanf("%d%d",&p,&q);
        Add(p,q,(i<<1)-1);
        Add(q,p,i<<1);
    }
    dfs(1,0);
    for(int i=1;i<=Q;i++)
    {
        char ch='\0';
        for(ch=getchar();!(ch=='-' || ch=='+' || ch=='*' || ch=='/');ch=getchar());
        if(ch=='+')
        {
            int u,v,r;
            scanf("%d%d%d",&u,&v,&r);
            long long increase=(long long)r%Mod;
            access(u);
            tree[u].rev^=1;
            swap(tree[u].son[0],tree[u].son[1]);
            access(v);
            update(v);
            tree[v].sum=(tree[v].sum+increase*tree[v].Size)%Mod;
            tree[v].add=increase;
        }
        if(ch=='-')
        {
            int u,v,p,q;
            scanf("%d%d%d%d",&u,&v,&p,&q);
            access(u);
            tree[u].rev^=1;
            swap(tree[u].son[0],tree[u].son[1]);
            access(v);
            tree[v].sum=(tree[v].sum-tree[u].sum+Mod)%Mod;
            tree[v].Size-=tree[u].Size;
            tree[u].fa1=tree[v].son[0]=0;
            access(q);
            tree[q].rev^=1;
            swap(tree[q].son[0],tree[q].son[1]);
            tree[q].fa2=p;
        }
        if(ch=='*')
        {
            int u,v,r;
            scanf("%d%d%d",&u,&v,&r);
            long long cheng=(long long)r%Mod;
            access(u);
            tree[u].rev^=1;
            swap(tree[u].son[0],tree[u].son[1]);
            access(v);
            update(v);
            tree[v].sum=tree[v].sum*cheng%Mod;
            tree[v].mult=cheng-1;
        }
        if(ch=='/')
        {
            int u,v;
            scanf("%d%d",&u,&v);
            access(u);
            tree[u].rev^=1;
            swap(tree[u].son[0],tree[u].son[1]);
            access(v);
            printf("%d\n",(int)tree[v].sum);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值