【BZOJ2759】一道动态树的好题

来源:互联网 发布:软件研发过程模型 编辑:程序博客网 时间:2024/05/16 14:56

2759: 一个动态树好题

Time Limit: 10 Sec Memory Limit: 128 MB
Description

有N个未知数x[1..n]和N个等式组成的同余方程组:
x[i]=k[i]*x[p[i]]+b[i] mod 10007
其中,k[i],b[i],x[i]∈[0,10007)∩Z
你要应付Q个事务,每个是两种情况之一:
一.询问当前x[a]的解
A a
无解输出-1
x[a]有多解输出-2
否则输出x[a]
二.修改一个等式
C a k[a] p[a] b[a]

Input

N
下面N行,每行三个整数k[i] p[i] b[i]
Q
下面Q行,每行一个事务,格式见题目描述

Output

对每个询问,输出一行一个整数。
对100%的数据,1≤N≤30000,0≤Q≤100000,时限2秒,其中询问事务约占总数的80%

Sample Input

5

2 2 1

2 3 2

2 4 3

2 5 4

2 3 5

5

A 1

A 2

C 5 3 1 1

A 4

A 5

Sample Output

4276

7141

4256

2126

确实是道动态树的好题啊= =
以下p=10007。
如果我们把每个i看作是一个点,p(i)看作是i的父亲,显然整个方程组会形成一个基环森林,而每个连通块都是一棵基环外向树,根据经验,我们可以拆掉环上的某条边,因此我们便得到了一个森林,便转化为了动态树的问题(ZGY神犇说可以用仙人掌来做,可是我不会= =)。
首先考虑如何回答询问。显然手动拆掉的那条边的起点是整棵树的根,我们可以对根记一个special father(以下简记为s)表示拆掉那条边的终点,我们设s的值为x,那么对于每个点我们都可得出它的值与x的线性关系。我们找到s后,实际上我们得到了s与它自己的线性关系,即我们得到了一个形如xkx+b(mod p)的同余方程。那么当k=1时,若b=0则有多组解,反之则无解。其它的,由于p是质数,使用数论知识稍加分析可得该同余方程有且仅有一个解,直接使用扩展欧几里德算法求解即可。注意讨论k=0的情况,因为C语言中负数的除法的特性会使扩展欧几里德算法失效。
修改的话,对于k和b的话access+splay直接改就可以了;修改父亲的时候要分多种情况讨论:如果这个点就是根,那么直接修改它的special father;反之,如果这个点原本在环上,此时我们需要把那条去掉的边补上。当它与它的父亲的边切掉后,它暂时成为了根,与新的父亲连接的时候,如果他们在一棵树上,便形成了一个环,赋值special father即可,否则直接连接。

#include<iostream>#include<cstdio>#define maxn 30000using namespace std;const int p=10007;struct data{    int k,b;    data(){k=1,b=0;}    data(int k,int b):k(k),b(b){}    int cal(int x){return (k*x+b)%p;}};data operator+(data a,data b){    data ret;    ret.k=a.k*b.k%p;    ret.b=(a.b*b.k%p+b.b)%p;    return ret;}void exgcd(int a,int b,int &x,int &y){    if(!b)x=1,y=0;    else{        exgcd(b,a%b,y,x);        y-=a/b*x;    }}struct linkcuttree{    int ch[maxn+10][2],fa[maxn+10],sfa[maxn+10];    data val[maxn+10],sum[maxn+10];    int rc(int fa,int o){return ch[fa][1]==o;}    int top(int o){return ch[fa[o]][0]!=o&&ch[fa[o]][1]!=o;}    void pushup(int o){sum[o]=sum[ch[o][0]]+val[o]+sum[ch[o][1]];}    int vis[maxn+10],ins[maxn+10];    void dfs(int u){        ins[u]=vis[u]=1;        int v=fa[u];        if(ins[v]){            fa[u]=0;            sfa[u]=v;               }        if(!vis[v])dfs(v);        ins[u]=0;    }    void init(int n){        for(int i=1;i<=n;i++){            int k,b;            scanf("%d%d%d",&k,&fa[i],&b);            val[i]=sum[i]=data(k,b);        }        for(int i=1;i<=n;i++)if(!vis[i])dfs(i);    }    void rot(int o){        int f=fa[o],r=rc(f,o);        if(!top(f))fa[ch[fa[f]][rc(fa[f],f)]=o]=fa[f];        else fa[o]=fa[f];        fa[ch[f][r]=ch[o][r^1]]=f;        fa[ch[o][r^1]=f]=o;        pushup(f);        pushup(o);    }    void splay(int o){        while(!top(o)){            if(!top(fa[o])&&rc(fa[fa[o]],fa[o])==rc(fa[o],o))rot(fa[o]);            rot(o);        }    }    void access(int u){        int v=0;        while(u){            splay(u);            ch[u][1]=v;            pushup(u);            v=u;            u=fa[u];        }    }    int findroot(int u){        access(u);        splay(u);        int ro=u;        while(ch[ro][0])ro=ch[ro][0];        splay(ro);        return ro;    }    int query(int u){        access(u);        splay(u);        data v1=sum[u];        int ro=findroot(u),f=sfa[ro];        access(f);        splay(f);        data v2=sum[f];        if(v2.k==1)return v2.b?-1:-2;        if(v2.k==0)return v1.cal(v2.b);        int x,y;        exgcd(v2.k-1,p,x,y);        return v1.cal((p-x)%p*v2.b%p);    }    void cut(int u){        access(u);        splay(u);        fa[ch[u][0]]=0;        ch[u][0]=0;        pushup(u);    }    void join(int u,int f){        access(u);        splay(u);        fa[u]=f;    }    int oncirclr(int u,int ro){        int f=sfa[ro];        if(u==f)return 1;        access(f);        splay(f);        splay(u);        return !top(f);    }    void update(int u,int f,int k,int b){        access(u);        splay(u);        val[u]=data(k,b);        pushup(u);        int ro=findroot(u);        if(u==ro){            int rf=findroot(f);            if(rf==ro)sfa[u]=f;            else{                sfa[u]=0;                join(u,f);            }        }else{            if(oncirclr(u,ro)){                cut(u);                join(ro,sfa[ro]);                sfa[ro]=0;                int rf=findroot(f);                if(rf==u)sfa[u]=f;                else join(u,f);            }else{                cut(u);                int rf=findroot(f);                if(rf==u)sfa[u]=f;                else join(u,f);            }           }    }}lct;int main(){    int n;    scanf("%d",&n);    lct.init(n);    int q;    scanf("%d",&q);    char e[2];    int x,k,b,f;    while(q--){        scanf("%s%d",e,&x);        if(e[0]=='A')printf("%d\n",lct.query(x));        else{            scanf("%d%d%d",&k,&f,&b);            lct.update(x,f,k,b);        }    }    return 0;}
3 0
原创粉丝点击