把 pi 设为 i 的父亲,这样会变成一个基环森林
可以发现一个点有解当且仅当这个店所在联通块存在环
对于环,可以任取一点作为根,根原本的父亲看做一条特殊的边。
那么用LCT可以维护出一个点与这个点所在联通块的根的关系,也就是
那么可以根据根与根的父亲的关系求出根的值,然后就可以求出这棵基环树上任意一点的值。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=30010,P=10007;
int inv[P+5];
struct key{
int x,y;
key(int a=0,int b=0):x(a),y(b){}
friend key operator +(key a,key b){
return key(a.x*b.x%P,(a.y*b.x+b.y)%P);
}
};
struct NODE{
key v,sum;
NODE *ch[2],*f,*s;
int rev;
}a[N];
inline int isl(NODE *x){
return !x->f || (x->f->ch[0]!=x && x->f->ch[1]!=x);
}
inline int isr(NODE *x){
return x->f && x->f->ch[1]==x;
}
inline void Up(NODE *x){
x->sum=x->v;
if(x->ch[0]){
x->sum=x->ch[0]->sum+x->sum;
}
if(x->ch[1]){
x->sum=x->sum+x->ch[1]->sum;
}
}
inline void Push(NODE *x){
if(!x->rev) return ;
swap(x->ch[0],x->ch[1]);
if(x->ch[0]) x->ch[0]->rev^=1;
if(x->ch[1]) x->ch[1]->rev^=1;
x->rev^=1;
}
inline void rot(NODE *x){
NODE *y=x->f,*z=y->f; int wh=isr(x);
if(!isl(y)) z->ch[isr(y)]=x; x->f=z;
if(y->ch[wh]=x->ch[wh^1]) y->ch[wh]->f=y;
(x->ch[wh^1]=y)->f=x; Up(y); Up(x);
}
void PUSHTOP(NODE *x){
if(!isl(x)) PUSHTOP(x->f);
Push(x);
}
inline void splay(NODE *x){
PUSHTOP(x);
for(;!isl(x);rot(x)) if(!isl(x->f)) rot(isr(x)^isr(x->f)?x:x->f);
}
inline void access(NODE *x){
for(NODE *t=0;x;x=x->f)
splay(x),x->ch[1]=t,t=x,Up(x);
}
inline void reverse(NODE *x){
access(x); splay(x); x->rev^=1;
}
int n,q,k[N],p[N],b[N];
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline NODE *Root(NODE *x){
access(x); splay(x);
while(x->ch[0]) x=x->ch[0];
return x;
}
inline bool Un(NODE *x,NODE *y){
return Root(x)==Root(y);
}
inline int GET(NODE *x){
NODE *y=x->s;
int K=k[x-a],B=b[x-a];
access(y); splay(y);
B=(B+K*y->sum.y)%P;
K=K*y->sum.x%P;
K=(K+P-1)%P; B=(P-B)%P;
if(!K) return -1;
return B*inv[K]%P;
}
int main(){
rea(n);
inv[1]=1;
for(int i=2;i<P;i++) inv[i]=(P-P/i)*inv[P%i]%P;
for(int i=1;i<=n;i++){
rea(k[i]);rea(p[i]);rea(b[i]);
if(Un(a+i,a+p[i])){
reverse(a+i);
a[i].v=key(1,0);
a[i].s=a+p[i];
}
else{
a[i].f=a+p[i];
a[i].v=a[i].sum=key(k[i],b[i]);
}
access(a+i);
}
rea(q);
while(q--){
char opt;
while((opt=nc())!='A' && opt!='C');
if(opt=='A'){
int x; rea(x);
NODE *rt=Root(a+x);
if(!rt->s){
puts("-2"); continue;
}
access(a+x); splay(a+x);
int k=a[x].sum.x,b=a[x].sum.y,cur=GET(rt);
if(cur<0) printf("%d\n",cur);
else printf("%d\n",(k*cur+b)%P);
}
else{
int x;
rea(x); rea(k[x]); rea(p[x]); rea(b[x]);
NODE *rt=Root(a+x);
if(rt==a+x){
rt->s=0;
access(rt); splay(rt);
if(Un(a+x,a+p[x]))
rt->s=a+p[x],rt->v=key(1,0),Up(rt);
else{
rt->f=a+p[x]; rt->sum=rt->v=key(k[x],b[x]);
access(rt);
}
}
else{
access(a+x); splay(a+x);
if(a[x].ch[0]) a[x].ch[0]->f=0;
a[x].ch[0]=0;
if(!Un(rt,rt->s)){
access(rt); splay(rt);
rt->f=rt->s; rt->s=0;
rt->v=rt->sum=key(k[rt-a],b[rt-a]);
Up(rt);
}
access(a+x); splay(a+x);
if(Un(a+x,a+p[x])){
reverse(a+x); a[x].s=a+p[x];
a[x].sum=a[x].v=key(1,0); Up(a+x);
}
else{
a[x].f=a+p[x]; a[x].sum=a[x].v=key(k[x],b[x]);
Up(a+x);
}
}
}
}
return 0;
}