%%%PoPoQQQ:http://blog.csdn.net/popoqqq/article/details/40436165
“题目大意:给定n个形如xi=ki*x_pi+bi mod p的同余方程组 支持修改操作和求解操作
确实好题 感谢此题作者 顺便吐槽一下作者的Splay不加空节点太蛋疼了0.0
将每个点i的父亲设为pi 我们将会得到一座基环树林 将环上的一条边拆掉,在边的起始节点新开个域special_father记录这条边(P.S:好浪费 但是没办法)
于是我们得到了一座森林 显然可以用LCT来维护 每个节点的权值是个二元组(k,b),记录每个点关于答案的线性关系,合并时左侧代入右侧中
查询时将root的special_father进行Access+Splay操作 然后借助这个环通过EXGCD求出root->special_father的值 然后Access+Splay(x)代入出解
若环上k=1 讨论b 若b=0则无穷多解 否则无解 注意k=0时要加一些处理 正常求EXGCD求不出来
单点修改 有向图 没有标记 爽爆了!
修改x的父节点时需要讨论:
首先切掉原先的父节点
如果x是所在树的根 直接切掉special_father
如果x不是根,切掉x与父节点的联系,然后讨论x是否在环上
设x所在树的根节点为root
若root->special_father所在树的根不为root 则x在环上 将root的special_father变为root的fa节点
否则切断父节点完毕
然后讨论新的父节点f是否在x的子树中
若在,将x的special_father设为f
若不在,将x的fa设为f”
#include<cstdio> #include<cstdlib> #include<algorithm> #define P 10007 using namespace std; typedef long long ll; typedef pair<ll,ll> abcd; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline void read(ll &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline void read(char &x){ for (x=nc();x!='A' && x!='C';x=nc()); } namespace Math{ #define N 10007 inline abcd EXGCD(ll a,ll b){ if (a<b) { abcd ret=EXGCD(b,a); return abcd(ret.second,ret.first); } if (!b) return abcd(1,0); abcd ret=EXGCD(b,a%b); return abcd(ret.second,ret.first-a/b*ret.second); } inline int Solve(ll A,ll B){ A%=N; B%=N; if (!A && !B) return -2; if (!A && B) return -1; if (!B && A) return 0; abcd E=EXGCD(A,N); ll D=A*E.first+N*E.second,X; if (B%D==0) { if (D!=1) return -2; X=E.first*(B/D); X=((X%(N/D))+N/D)%(N/D); return X; } else return -1; } } struct data{ ll k,b; data(int k=1,int b=0):k(k),b(b) { } friend data operator + (const data &A,const data &B){ data ret; (ret.k=A.k*B.k)%=P; (ret.b=B.k*A.b+B.b)%=P; return ret; } }; struct Splay{ struct node{ int size,idx; node *p,*ch[2],*fat,*sf; data dat,sum; inline void setc(node *c,int d) { ch[d]=c; c->p=this; } inline bool dir() { return p->ch[1]==this; } inline void update() { size=ch[1]->size+ch[0]->size+1; sum=ch[0]->sum+dat+ch[1]->sum; } }*null,Mem[30005]; Splay() { null=Mem; null->p=null->ch[0]=null->ch[1]=null->fat=null->sf=null; null->size=0; null->sum=data(1,0); } inline void rot(node *x){ if (x==null || x->p==null) return; bool d=x->dir(); node *p=x->p; if (p->p!=null) p->p->setc(x,p->dir()); else x->p=null; p->setc(x->ch[d^1],d); x->setc(p,d^1); p->update(); x->update(); swap(x->fat,p->fat); } inline void splay(node *x){ if (x==null) return; while (x->p!=null) if (x->p->p==null) rot(x); else x->dir()==x->p->dir()?(rot(x->p),rot(x)):(rot(x),rot(x)); } inline node *Access(node *x){ node *y=null; while (x!=null) { splay(x); x->ch[1]->p=null; x->ch[1]->fat=x; x->setc(y,1); y->fat=null; x->update(); y=x; x=x->fat; } return y; } inline void Link(node *x,node *y){ Access(x); splay(x); x->fat=y; Access(x); } inline void Cut(node *x){ Access(x); splay(x); x->ch[0]->p=null; x->ch[0]=null; x->fat=null; x->update(); } inline node *Root(node *x){ Access(x); splay(x); node *y=x; while (y->ch[0]!=null) y=y->ch[0]; return y; } inline bool Jud(node *x,node *y){ return Root(x)==Root(y); } inline data Query(node *x){ return Access(x)->sum; } }LCT; int n; Splay::node *pos[30005]; inline void Init(int n) { for (int i=1;i<=n;i++) pos[i]=LCT.Mem+i,pos[i]->p=pos[i]->ch[0]=pos[i]->ch[1]=pos[i]->fat=pos[i]->sf=LCT.null,pos[i]->size=1,pos[i]->idx=i; } inline void PCut(Splay::node *x){ if (x==LCT.Root(x)){ x->sf=LCT.null; return; } Splay::node *rt=LCT.Root(x),*sf=rt->sf; LCT.Cut(x); if (!LCT.Jud(sf,rt)) { rt->sf=LCT.null; LCT.Link(rt,sf); } } inline void PLink(Splay::node *x,Splay::node *y){ if (LCT.Root(y)==x){ x->sf=y; return; } LCT.Link(x,y); } int par[30005]; int main() { char order; int ip,Q,u,ik,ib; ll x0; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); Init(n); for (int i=1;i<=n;i++) { read(pos[i]->dat.k); read(par[i]); read(pos[i]->dat.b); pos[i]->update(); } for (int i=1;i<=n;i++) PLink(pos[i],pos[par[i]]); read(Q); while (Q--) { read(order); if (order=='A') { read(u); Splay::node *sf=LCT.Root(pos[u])->sf; data ret=LCT.Query(sf); ret.b=(-ret.b+P)%P; ret.k=(ret.k-1+P)%P; x0=Math::Solve(ret.k,ret.b); if (x0!=-1 && x0!=-2) { ret=LCT.Query(pos[u]); (x0=x0*ret.k+ret.b)%=P; } printf("%lld\n",x0); } else { read(u); read(ik); read(ip); read(ib); PCut(pos[u]); LCT.splay(pos[u]); pos[u]->dat=data(ik,ib); pos[u]->update(); PLink(pos[u],pos[ip]); } } return 0; }