BZOJ2631: tree

题解: LCT 类似维护一次函数 a*x+b 的双标记

/**************************************************************
    Problem: 2631
    User: c20161007
    Language: C++
    Result: Accepted
    Time:21336 ms
    Memory:9352 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
#include <vector>
#define ll  unsigned int
const int MAXN=1e5+10;
const int lth=51061;
using namespace std;
//ll readll(){
//    ll x=0,f=1;char ch=getchar();
//    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
//    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
//    return x*f;
//}
int readint(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
int ch[MAXN][2],pre[MAXN],rt[MAXN],size[MAXN],n,q;
ll key[MAXN],sum[MAXN],add[MAXN],res[MAXN],mul[MAXN];
void Treavel(int x)
{
    if(x)
    {
    //  cout<<x<<endl;
        Treavel(ch[x][0]);
        printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d,key=%2d\n",x,ch[x][0],ch[x][1],pre[x],size[x],key[x]);
        Treavel(ch[x][1]);
    }
}
void debug(int rp)
{
    printf("root:%d\n",rp);
    Treavel(rp);
}
void update(int r,ll vul1,ll vul2){
    if(!r) return ;
    sum[r]=((sum[r]*vul1)%lth+(size[r]*vul2)%lth)%lth;
    key[r]=((vul1*key[r])%lth+vul2)%lth;
    mul[r]=(mul[r]*vul1)%lth;
    add[r]=((add[r]*vul1)%lth+vul2)%lth;
}
void update_add(int r,ll vul){
    if(!r) return ;
    key[r]=(vul+key[r])%lth;
    sum[r]=(sum[r]+1ll*size[r]*vul)%lth;
    add[r]=(add[r]+vul)%lth;
}
void update_mul(int r,ll vul){
    if(!r) return ;
    key[r]=(key[r]*vul)%lth;
    sum[r]=(sum[r]*vul)%lth;
    mul[r]=(mul[r]*vul)%lth;
    add[r]=(add[r]*vul)%lth;
}
void update_res(int r){
    if(!r) return ;
    swap(ch[r][0],ch[r][1]);
    res[r]^=1;
}
void push(int x){
    if(res[x]){
        update_res(ch[x][0]);
        update_res(ch[x][1]);
        res[x]^=1;
    }
    update(ch[x][0],mul[x],add[x]);
    update(ch[x][1],mul[x],add[x]);
    mul[x]=1,add[x]=0;
}
void up(int x){
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
    sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+key[x])%lth;
}
void P(int r){
    if(!rt[r]) P(pre[r]);
    push(r);
}
void rotate(int x,int kind){
    int y=pre[x];
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(rt[y]) rt[y]=0,rt[x]=1;
    else ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];ch[x][kind]=y;pre[y]=x;
    up(y);
}
void splay(int x){
    P(x);
    //cout<<x<<"-----"<<rt[x]<<endl;
    while(!rt[x]){
        if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x);
        else{
            int y=pre[x];int kind=ch[pre[y]][0]==y;
            if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);
            else rotate(y,kind),rotate(x,kind); 
        }
    }
    up(x);
}
void access(int x){
    int y=0;
    //cout<<x<<endl;
    //cout<<pre[1]<<"-----"<<endl;
//  cout<<x<<" "<<pre[x]<<endl;
    while(x){
        splay(x);
        //debug(x);
        //cout<<x<<"------"<<y<<endl;
        if(ch[x][1]) rt[ch[x][1]]=1,pre[ch[x][1]]=x,ch[x][1]=0;
        ch[x][1]=y;
        up(x);
        if(y) rt[y]=0,pre[y]=x;
        y=x;x=pre[x];
    //  cout<<x<<" "<<y<<endl;
    }
    //debug(1);
    return ;
}
void mroot(int x){
    access(x);//debug(x);
    splay(x);//debug(x);
    //cout<<pre[1]<<"====="<<endl;
    //debug(x);
    update_res(x);
    //up(x);
    return ;
}
void operator_add(int u,int v,ll vul){
    mroot(u);access(v);splay(u);
    update_add(u,vul);
    return ;
}
void operator_chong(int u1,int v1,int u2,int v2){
    mroot(u1);access(v1);splay(v1);
    ch[v1][0]=0;up(v1);
    pre[u1]=pre[v1]=0;rt[u1]=rt[v1]=1;
    mroot(u2);pre[u2]=v2;
}
void operator_mul(int u,int v,ll vul){
    //cout<<u<<" "<<v<<endl;
//  cout<<u<<" "<<v<<" "<<pre[u]<<" "<<pre[v]<<endl;
//  debug(u);debug(v);
    mroot(u);
    //debug(u);
//  cout<<rt[v]<<endl;
    access(v);//debug(v);
    splay(u);
    update_mul(u,vul);
}
int operator_querty(int u,int v){
    //cout<<pre[u]<<" "<<pre[v]<<endl;
    //if(u==v) return key[u]%lth;
    mroot(u);//debug(u);
    //cout<<pre[1]<<"------"<<endl;
    access(v);//debug(v);
    splay(u);
//  debug(u);
    return sum[u]%lth;
}
vector<int>vec[MAXN];
void dfs(int v,int fa){
    pre[v]=fa;
    for(int i=0;i<vec[v].size();i++){
        if(vec[v][i]!=fa) dfs(vec[v][i],v);
    }
}
int main(){
    ios::sync_with_stdio(false);
    n=readint();q=readint();
    for(int i=1;i<=n;i++){
        ch[i][0]=ch[i][1]=pre[i]=add[i]=res[i]=0;
        size[i]=rt[i]=key[i]=sum[i]=mul[i]=1;
    }
    char ch;int u,v,u1,v1;ll x;
    for(int i=1;i<n;i++){
        u=readint();v=readint();
        vec[u].push_back(v);vec[v].push_back(u);
    }
    dfs(1,0);
    for(int i=1;i<=q;i++){
        scanf(" %c",&ch);u=readint();v=readint();
        if(ch=='+'){
            scanf("%d\n",&x);operator_add(u,v,x%lth);
        }
        else if(ch=='-'){
            scanf("%d\n",&u1);scanf("%d\n",&v1);
            operator_chong(u,v,u1,v1);
        }
        else if(ch=='*'){
            scanf("%d\n",&x);
            operator_mul(u,v,x%lth);
        }
        else printf("%d\n",operator_querty(u,v));
    }
    return 0;
}

 

2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 5381  Solved: 1811
[Submit][Status][Discuss]

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的余数。

Input

  第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作

Output

  对于每个/对应的答案输出一行

Sample Input

3 2
1 2
2 3
* 1 3 4
/ 1 1

Sample Output

4


HINT

数据规模和约定

10%的数据保证,1<=n,q<=2000

另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

100%的数据保证,1<=n,q<=10^5,0<=c<=10^4

posted @ 2018-08-12 00:10  wang9897  阅读(130)  评论(0编辑  收藏  举报