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\n",ask(x));
        else
        {
            scanf("%d%d%d",&tr[x].u.k,&F,&tr[x].u.b);
            Cut(x);Link(x,F);
        }
    }
    
    return 0;
}

 

posted @ 2019-01-11 13:25  AKCqhzdy  阅读(156)  评论(0编辑  收藏  举报