• bzoj2759: 一个动态树好题


    LCT补坑。。。

    经过我多年被树形思路题的狂虐加上LCT路牌的提示,终于想到了对于每个未知数建一个点建树

    观察柿子,它只有二元,我们可以理解为i被pi表示,那么pi在树上作为i的父亲,理解为i向pi连边,那么这个图就是一个内向基环树森林

    对于每棵基环树把环断开,以断开的出点为根,记录根被谁表示

    如何解方程呢?我们可以这么做:把树上的每一个点都用表示出根的未知数的未知数表示,只需用exgcd解出表示出根未知数的未知数,用一个未知数表示另一个未知数,用的就是k和b

    既然如此我们定义二元组(k,b)表示kx+b=当前未知数,x我们定

    那么直接输进来的k和b表示的就是用父亲表示当前节点

    要用表示出根的点表示当前节点,相当于要把当前点到根的k,b二元组合并

    稍微推一下:x0 = k1x1 + b1 = k1( k2x2 + b2 ) + b1 = k1k2x2 + k1b2 + b1

    这样的和并定义为(k2,b2)+(k1,b1),则有(k2,b2)+(k1,b1)=( k1k2 , k1b2+b1 )

    于是要维护的就是根到当前点二元组之和,注意不能反过来,不满足交换律

    可以splay维护,记录一下子树中的点的二元组按中序遍历加起来的和即可,那么对于当前点的影响就是左孩子的和+自己的二元组

    值得注意的是,cut的时候可能导致环的断裂,这时可以把根的出边再次尝试连接来避免出锅

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int mod=10007;
    
    int exgcd(int a,int b,int &x,int &y)
    {
        if(a==0)
        {
            x=0;y=1;
            return b;
        }
        else
        {
            int tx,ty;
            int d=exgcd(b%a,a,tx,ty);
            x=ty-b/a*tx;
            y=tx;
            return d;
        }
    }
    int solve(int A,int B,int K)
    {
        int x,y,d=exgcd(A,B,x,y);
        if(K%d!=0)return -1;
        else
        {
            x=(x*(K/d)%(B/d)+(B/d))%(B/d);
            y=(A*x-K)/B;
            return y;
        }
    }
    
    //--------------------------------------tool-------------------------------------------------------
    
    struct pa
    {
        int k,b;
        pa(){k=1,b=0;}
        pa(int K,int B){k=K,b=B;}
        friend pa operator +(pa p1,pa p2){return pa((p1.k*p2.k)%mod,(p2.k*p1.b+p2.b)%mod);}
    };
    struct trnode
    {
        int f,son[2];//base
        pa u,p;//p维护的是子树中中序遍历u和 
        //左孩子的中序遍历u和+自己的u=我用实根表示的方案
    }tr[31000];
    void update(int x)
    {
        int lc=tr[x].son[0],rc=tr[x].son[1];
        tr[x].p=pa(1,0);
        if(lc!=0)tr[x].p=(tr[x].p+tr[lc].p);
                 tr[x].p=(tr[x].p+tr[x].u);
        if(rc!=0)tr[x].p=(tr[x].p+tr[rc].p);
    }
    void rotate(int x,int w)
    {
        int f=tr[x].f,ff=tr[f].f;
        int R,r;
        
        R=f,r=tr[x].son[w];
        tr[R].son[1-w]=r;
        if(r!=0)tr[r].f=R;
        
        R=ff,r=x;
        if(R>0)
        {
                 if(tr[ff].son[0]==f)tr[R].son[0]=r;
            else if(tr[ff].son[1]==f)tr[R].son[1]=r;
        }
        tr[r].f=R;
        
        R=x,r=f;
        tr[R].son[w]=r;
        tr[r].f=R;
        
        update(f);
        update(x);
    }
    bool isroot(int x)
    {
        int f=tr[x].f;
        if(f<0||(tr[f].son[0]!=x&&tr[f].son[1]!=x))return true;
        return false;
    }
    void splay(int x)
    {
        while(isroot(x)==false)
        {
            int f=tr[x].f,ff=tr[f].f;
            if(isroot(f)==true)
            {
                     if(tr[f].son[0]==x)rotate(x,1);
                else if(tr[f].son[1]==x)rotate(x,0);
            }
            else 
            {
                     if(tr[ff].son[0]==f&&tr[f].son[0]==x)rotate(f,1),rotate(x,1);
                else if(tr[ff].son[1]==f&&tr[f].son[1]==x)rotate(f,0),rotate(x,0);
                else if(tr[ff].son[0]==f&&tr[f].son[1]==x)rotate(x,0),rotate(x,1);
                else if(tr[ff].son[1]==f&&tr[f].son[0]==x)rotate(x,1),rotate(x,0);
            }
        }
    }
    //~~~~~~~~~~~~~~~~~~~splay~~~~~~~~~~~~~~~~~~~~~~~~~ 
    
    void access(int x)
    {
        int y=0;
        while(x>0)
        {
            splay(x);
            tr[x].son[1]=y;
            update(x);
            y=x;x=tr[x].f;
        }
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(tr[x].son[0]!=0)x=tr[x].son[0];
        return x;
    }
    //~~~~~~~~~~~~~~~~~~~~~~in~~~~~~~~~~~~~~~~~~~~~~~~~
    
    void Link(int x,int y)
    {
        if(findroot(x)==findroot(y))
        {
            access(x),splay(x);
            tr[x].f=-y;
        }
        else
        {
            access(x);splay(x);
            tr[x].f=y;
        }
    }
    void Cut(int x)
    {
        access(x);splay(x);
        if(tr[x].son[0]==0)tr[x].f=0;
        else
        {
            int y=tr[x].son[0],p=-tr[x].f;    
            tr[y].f=0,tr[x].son[0]=0;
            Link(findroot(y),p);
            update(x);
        }
    }
    pa getpa(int x)
    {
        access(x),splay(x);
        return tr[tr[x].son[0]].p+tr[x].u;
    }
    int ask(int x)
    {
        pa g=getpa(x),e=getpa(-tr[x].f);
        e.k--;if(e.k<0)e.k+=mod;
        if(e.k==0)return -1-(e.b==e.b);
        int d=solve(mod,e.k,e.b);
        if(d==-1)return -1;
        else return (g.k*d+g.b)%mod;
    }
    //~~~~~~~~~~~~~~~~~~~~~out~~~~~~~~~~~~~~~~~~~~~~~~~
    
    //-------------------------------------------------lCT-----------------------------------------------------------------------
    
    char ss[5];
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int n,F;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&tr[i].u.k,&F,&tr[i].u.b);
            tr[i].p=tr[i].u;
            Link(i,F);
        }
        
        int Q,x;
        scanf("%d",&Q);
        while(Q--)
        {
            scanf("%s%d",ss+1,&x);
            if(ss[1]=='A')printf("%d
    ",ask(x));
            else
            {
                scanf("%d%d%d",&tr[x].u.k,&F,&tr[x].u.b);
                Cut(x);Link(x,F);
            }
        }
        
        return 0;
    }
  • 相关阅读:
    CentOS6.0 yum php mcrypt 扩展安装问题
    WordPress入门系列之基本设置
    ./configure 配置文件时出错checking for g++... no
    锐捷硬件防火墙
    CentOS 安装php mcrypt和mbstring的扩展
    (转)在asp.net 2.0中使用SqlBulkCopy类迁移数据
    正则表达式对象&&String对象
    SQL Server 和 SQLite 时间函数汇总
    FreeBSD下nginx并支持php配置详解
    从Ports安装MySQL
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10254655.html
Copyright © 2020-2023  润新知