【BZOJ】2759一个动态树好题-LCT

题解

真·动态树好题。
根据题目要求,我们以点i向其p[i]连边,必然会得到基环树林,每个解可以在所在环里得解。我们将每个环上的一条边连成虚边,该边所连接的就是LCT里的root和p[root](记为rt的spf(special_father))。
我们在update是可以维护每个点的k,b,不断向上累计系数,更新到rt.
在求当前a的值时候,我们可以先找到rt,把rt的spf access+splay绕到顶点,此时取出rt_spf所记录的k,b系数,设root的值为x,可得方程 k x + b = x 。所以若 k = 1 b = 0 ,则有无穷解,若 k = 1 , b 0
对于修改操作,若a不为root,先把a和f切掉,看rt_spf和rt还在不在同一颗树上,不在了就把root_spf变成root_f,因为现在a所在的环从a断开了,否则直接切掉a。然后看a的修改后p在不在同一颗树内,在就a access+splay 然后a_spf连接p[a],否则连f。


代码

膜了一发PO姐的代码,感觉指针写起来莫名爽快。

 #include<cstdio>
 #include<cstring>
 #include<cmath>
 #include<algorithm>
 #include<cctype>
 #define mod 10007
 #define gc getchar
 using namespace std;
 const int N=3e4+10;
 int fa[N],n,m,v[N],cnt;
 char o[10];

 inline int rd()
 {
    char ch=gc();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=gc();}
    return x*f;
 }

 struct line{
    int k,b;
    line operator +(const line &u)const{
       return (line){k*u.k%mod,(u.k*b%mod+u.b)%mod}; 
    }
    int F (int x){return (k*x+b)%mod;}
 };

 struct Node{
    Node *ls,*rs,*f,*sf;
    line num,sum;
    Node(int k,int b);
    void pushup();
 }*null= new Node(1,0),*tree[N];

 Node :: Node(int k,int b)
 {
    ls=rs=f=sf=null;
    num.k=sum.k=k;
    num.b=sum.b=b;
 }

 void Node :: pushup()
 {sum=ls->sum+num+rs->sum;}

 void dfs(int x)
 {
    v[x]=cnt;
    if(v[fa[x]]==cnt){
        tree[x]->sf=tree[fa[x]];
        return;
    }
    tree[x]->f=tree[fa[x]];
    if(!v[fa[x]]) dfs(fa[x]);
 }

 void Zig(Node *x)
 {
    Node *y=x->f;Node *z=y->f;
    y->ls=x->rs;x->rs->f=y;x->rs=y;y->f=x;x->f=z;
    if(z->ls==y) z->ls=x;else if(z->rs==y) z->rs=x;
    y->pushup();
 }

 void Zag(Node *x)
 {
    Node* y=x->f;Node* z=y->f;
    y->rs=x->ls;x->ls->f=y;x->ls=y;y->f=x;x->f=z;
    if(z->ls==y) z->ls=x;else if(z->rs==y) z->rs=x;
    y->pushup();
 }

 void splay(Node *x)
 {
    Node *y,*z;
    while((x->f->ls==x)||(x->f->rs==x)){
        y=x->f;z=y->f;
        if(y->ls==x){
            if(z->ls==y) Zig(y);
           Zig(x);
        }else{
            if(z->rs==y) Zag(y);
           Zag(x);
        }
    }
    x->pushup();
 }

 inline void access(Node *x)
 {
    Node *u=null;
    for(;x!=null;x=x->f){
        splay(x);
        x->rs=u;
        x->pushup();
        u=x;
    }
 }

 Node* fdrt(Node *x)
 {
     access(x);splay(x);Node *u=x;
     for(;u->ls!=null;u=u->ls);
     return u;
 }

 pair<int,int>exgcd(int x,int y)
 {
    if(!y) return make_pair(1,0);
    pair<int,int>ret=exgcd(y,x%y);
    return make_pair(ret.second,ret.first-x/y*ret.second);
 }

 inline int inv(int x)
 {return (exgcd((x%mod+mod)%mod,mod).first%mod+mod)%mod;}

 int query(Node *x)
 {
    Node *rt=fdrt(x);
    access(rt->sf);splay(rt->sf);
    int K=rt->sf->sum.k,B=rt->sf->sum.b;
    if(K==1){
       if(B==0) return -2;
       else return -1;
    }
    int ret=(mod-B)*inv(K-1)%mod;
    access(x);splay(x);
    return x->sum.F(ret);
 }

 void modify(Node *x,Node *y,int k,int b)
 {
    Node* rt=fdrt(x);
    x->num.k=k;x->num.b=b;x->pushup();
    if(rt==x) x->sf=null;
    else{
        access(x);splay(x);
        x->ls->f=null;x->ls=null;x->pushup();
        if(fdrt(rt->sf)!=rt){
            access(rt);splay(rt);
            rt->f=rt->sf;rt->sf=null;
        }
    }
    access(x);splay(x);
    if(fdrt(y)!=x) x->f=y;
    else x->sf=y;
 }

 int main(){
    int i,j,k,p,a,b;
    n=rd();
    for(i=1;i<=n;++i){
        k=rd();fa[i]=rd();b=rd();
        tree[i]= new Node(k,b);
    }
    for(i=1;i<=n;++i) if(!v[i]) {cnt++;dfs(i);}
    m=rd();
    while(m--){
        scanf("%s",o);
        if(o[0]=='A'){a=rd();printf("%d\n",query(tree[a]));}
        else{a=rd();k=rd();p=rd();b=rd();modify(tree[a],tree[p],k,b);}
    }
 }

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80556357
今日推荐