果然是一道动态树好题。
《论LCT的正确使用方法》以及《出题人真会玩》系列
把每个点向p连一条边,那么这是一个基环树森林。
先从环上拆下来一条边并记录这条边指向的点,然后这玩意就变成了一坨有根树。
设根为x1,根指向的点为x2,那么所有点都可以用关于x2的一次函数表示。然后用x2本身的一次函数可以解出x2。
然后用LCT维护这坨有根树。
splay上每个点维护用这个点子树中最小(最靠左,原树深度最小)的点在原树中的父亲表示最大(最靠右,原树深度最大)的点的一次函数。
然后找每个点的表示只需要access这个点,然后splay根的一次函数就是这个点的表示。
对于修改父亲有一坨分类讨论,细节看代码吧。。
#include <bits/stdc++.h>
using namespace std;
#define N 31000
#define mod 10007
#define which(x) (ch[fa[x]][1]==x)
int n,Q,tim;
int fa[N],dir[N],vis[N],ch[N][2],ni[11000];
char s[4];
struct node
{
int k,b;
node(){}
node(int k,int b):k(k),b(b){}
friend node operator + (const node &r1,const node &r2)
{return node(r1.k*r2.k%mod,(r2.k*r1.b%mod+r2.b)%mod);}
}a[N],sum[N];
void init()
{
ni[1]=1;
for(int i=2;i<mod;i++)
ni[i]=(mod-mod/i)*ni[mod%i]%mod;
}
void dfs(int x)
{
if(vis[x])return;
vis[x]=tim;
if(vis[fa[x]]==tim)
{
dir[x]=fa[x];
fa[x]=0;
}
else dfs(fa[x]);
}
int isroot(int x)
{return !fa[x]||ch[fa[x]][which(x)]!=x;}
void pushup(int x)
{
sum[x]=a[x];
if(ch[x][0])sum[x]=sum[ch[x][0]]+a[x];
if(ch[x][1])sum[x]=sum[x]+sum[ch[x][1]];
}
void rotate(int x)
{
int y=fa[x],k=which(x);
ch[y][k]=ch[x][k^1];
ch[x][k^1]=y;
if(!isroot(y))
ch[fa[y]][which(y)]=x;
fa[x]=fa[y];fa[y]=x;
fa[ch[y][k]]=y;
pushup(y);pushup(x);
}
void splay(int x)
{
while(!isroot(x))
{
int y=fa[x];
if(isroot(y))rotate(x);
else
{
if(which(x)^which(y))
rotate(x);
else rotate(y);
rotate(x);
}
}
}
void access(int x)
{
int t=0;
while(x)
{
splay(x);
ch[x][1]=t;
pushup(x);
t=x;x=fa[x];
}
}
int findroot(int x)
{
access(x);splay(x);
while(ch[x][0])x=ch[x][0];
splay(x);
return x;
}
int inc(int x,int y)
{
access(dir[y]);splay(dir[y]);
splay(x);
return x==dir[y]||!isroot(dir[y]);
}
void cut(int x)
{
access(x);splay(x);
ch[x][0]=fa[ch[x][0]]=0;
pushup(x);
}
int main()
{
//freopen("tt.in","r",stdin);
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&a[i].k,&fa[i],&a[i].b);
for(int i=1;i<=n;i++)
if(!vis[i])tim++,dfs(i);
scanf("%d",&Q);
for(int x,k,p,b;Q--;)
{
scanf("%s",s+1);
if(s[1]=='A')
{
scanf("%d",&x);
access(x);splay(x);
node t1=sum[x];
int t=findroot(x);
access(dir[t]);splay(dir[t]);
node t2=sum[dir[t]];
if(t2.k==1)
{
if(t2.b)puts("-1");
else puts("-2");
continue;
}
int v1=ni[(1-t2.k+mod)%mod]*t2.b%mod;
printf("%d\n",(t1.k*v1%mod+t1.b)%mod);
}
else
{
scanf("%d%d%d%d",&x,&k,&p,&b);
access(x);splay(x);
a[x]=node(k,b);pushup(x);
int t=findroot(x);
if(t==x)
{
if(findroot(p)==t)dir[t]=p;
else dir[t]=0,fa[t]=p;
}
else
{
if(inc(x,t))
{
cut(x);
access(t);splay(t);
fa[t]=dir[t];dir[t]=0;
if(findroot(p)==x)dir[x]=p;
else fa[x]=p;
}
else
{
cut(x);
if(findroot(p)==x)dir[x]=p;
else fa[x]=p;
}
}
}
}
return 0;
}