bzoj2631 tree(伍一鸣)

LCT模板题

坑死我了。

首先会超int,这里就不知不觉wa了几次,之后还是WA,以为模板不行,改来改去还是WA。

最后发现数据范围结点下标没有说明.....改成最大范围的结点下标后终于A了

感觉还是得写个动态的模板啊。

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,102400000")
#define maxn 100005
#define maxm 1000005
#define INF 1000000007
#define LINF 1000000000000001LL
#define LL long long
#define MOD 51061
struct node
{
    int to,next;
} edge[maxn<<1];
int head[maxn],esum;
inline void addedge(int u,int v)
{
    edge[esum].to=v,edge[esum].next=head[u],head[u]=esum++;
}
int n,m;
int ch[maxn][2],pre[maxn];
int chnum[maxn];
bool rev[maxn];
LL val[maxn],add[maxn],mul[maxn],sum[maxn];
bool rt[maxn];
void dfs(int u)
{
    for(int i=head[u],v; ~i; i=edge[i].next)
    {
        v=edge[i].to;
        if(pre[v]) continue;
        pre[v]=u;
        dfs(v);
    }
}
inline void update(int x,LL a,LL b)
{
    add[x]=(add[x]*a+b)%MOD;
    val[x]=(val[x]*a+b)%MOD;
    sum[x]=(sum[x]*a+b*(LL)chnum[x])%MOD;
    mul[x]=(mul[x]*a)%MOD;
}
inline void push_up(int x)
{
    sum[x]=val[x],chnum[x]=1;
    chnum[x]+=chnum[ch[x][0]],sum[x]+=sum[ch[x][0]];
    chnum[x]+=chnum[ch[x][1]],sum[x]+=sum[ch[x][1]];
    sum[x]%=MOD;
}
inline void push_down(int x)
{
    if (rev[x])
    {
        swap(ch[x][0],ch[x][1]);
        rev[ch[x][0]]^=1;
        rev[ch[x][1]]^=1;
        rev[x] = 0;
    }
    if(mul[x]!=1||add[x])
    {
        update(ch[x][0],mul[x],add[x]);
        update(ch[x][1],mul[x],add[x]);
        mul[x]=1,add[x]=0;
    }
}
///旋转操作,c=0左旋,c=1右旋
inline void Rotate(int x,int c)
{
    int y=pre[x],z=pre[y];
    ch[y][!c]=ch[x][c];
    pre[ch[x][c]]=y;
    pre[x]=z;
    if(ch[z][0]==y) ch[z][0]=x;
    if(ch[z][1]==y) ch[z][1]=x;
    ch[x][c]=y,pre[y]=x;
    if(rt[y]) rt[y]=0,rt[x]=1;
    push_up(y);
}
///将结点x转到结点tag的下面
inline void Splay(int x)
{
    int y,z;
    while(!rt[x])
    {
        if(rt[y=pre[x]])
        {
            push_down(y),push_down(x);
            if(ch[y][0]==x) Rotate(x,1);
            else Rotate(x,0);
        }
        else
        {
            z=pre[y];
            push_down(z),push_down(y),push_down(x);
            if(ch[z][0]==y)
            {
                if(ch[y][0]==x)
                    Rotate(y,1),Rotate(x,1);
                else Rotate(x,0),Rotate(x,1);
            }
            else
            {
                if(ch[y][0]==x)
                    Rotate(x,1),Rotate(x,0);
                else Rotate(y,0),Rotate(x,0);
            }
        }
    }
    push_up(x);
}
///将u到root的路径转换成实边
///返回u所在树的根结点
int Access(int u)
{
    int v=0;
    for(; u; u=pre[v=u])
    {
        Splay(u);///旋转之后,若u到根都是实边就可直接跳出
        push_down(u);
        rt[ch[u][1]]=1, rt[ch[u][1]=v]=0;
        push_up(u);
    }
    return v;
}
int Lca(int u,int v)
{
    Access(u);
    return Access(v);
}
void MakeRoot(int u)
{
    rev[Access(u)]^=1;
    Splay(u);
}
///找到u所在树的根
int FindRoot(int u)
{
    for(u=Access(u); push_down(u),ch[u][0]; u=ch[u][0]) ;
    return u;
}
///先将u设为根,然后pre[u]=v,最后打通u到v所在树的根
bool Link(int u,int v)
{
//    if(FindRoot(u)==FindRoot(v))
//    {
//        puts("-1");
//        return 0;
//    }
    MakeRoot(u);
    pre[u]=v;
    Access(u);
    return 1;
}
///先MR(x); 然后Access(y),Splay(y)。
///将u设为根节点,并使v和他的父节点断开
bool Cut(int u,int v)
{
    MakeRoot(u);
    Access(v);
    Splay(v);
    rt[ch[v][0]]=1;
    pre[ch[v][0]]=pre[v];
    pre[v]=ch[v][0]=0;
    push_up(v);
    return 1;
}
LL Query(int u,int v)
{
//    if(FindRoot(u)!=FindRoot(v)) return -1;
    MakeRoot(u);
    Access(v);
    Splay(v);
    return sum[v];
}

bool Modify(int u,int v,int a,int b)
{
//    if(FindRoot(u)!=FindRoot(v))
//    {
//        puts("-1");
//        return 0;
//    }
    MakeRoot(u);
    Access(v);
    Splay(v);
    update(v,(LL)a,(LL)b);
    return 1;
}

int main()
{
    char op[3];
    int u,v,d,u1,v1;
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif
    while(~scanf("%d%d",&n,&m))
    {
        esum=0;
        for(int i=0; i<maxn; i++)
        {
            rt[i]=1,mul[i]=1;
            val[i]=1;
            rev[i]=0;
            ch[i][0]=ch[i][1]=pre[i]=0;
            add[i]=0;
            head[i]=-1;
        }
        for(int i=0; i<n-1; i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        pre[u]=-1;
        dfs(u);
        pre[u]=0;
        while(m--)
        {
            scanf("%s%d%d",op,&u,&v);
            if(op[0]=='+')
            {
                scanf("%d",&d);
                Modify(u,v,1,d);
            }
            else if(op[0]=='-')
            {
                scanf("%d%d",&u1,&v1);
                Cut(u,v);
                Link(u1,v1);
            }
            else if(op[0]=='*')
            {
                scanf("%d",&d);
                Modify(u,v,d,0);
            }
            else printf("%lld\n",Query(u,v));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值