Description:
有
N
N
个未知数和
N
N
个等式组成的同余方程组:
mod
m
o
d
10007
10007
其中,
k[i],b[i],x[i]∈[0,10007)∩Z
k
[
i
]
,
b
[
i
]
,
x
[
i
]
∈
[
0
,
10007
)
∩
Z
你要应付
Q
Q
个事务,每个是两种情况之一:
一.询问当前的解
A
A
无解输出
−1
−
1
x[a]
x
[
a
]
有多解输出
−2
−
2
否则输出
x[a]
x
[
a
]
二.修改一个等式
C
C
k[a]
k
[
a
]
p[a]
p
[
a
]
b[a]
b
[
a
]
Solution:
我们可以发现这些关系构成了一个基环森林的形式,每个数把自己的
p
p
看作祖先,只要把祖先解出来即可解出自己。上每个点维护展开的
kx+b
k
x
+
b
形式,由于是基环树,在根额外维护多出的边。由于根肯定在环上,那么先把根的解出来,再提取出到根的路径,带入维护的
kx+b
k
x
+
b
即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 3e4 + 5, P = 10007;
int n, m;
char opt[10];
int f[maxn];
namespace lct {
struct node {
int f, spf, ch[2];
} t[maxn];
struct data {
int k, b;
data() {}
data(int _k, int _b) : k(_k), b(_b) {}
data friend operator + (const data &a, const data &b) {
return data(a.k * b.k % P, (a.b * b.k + b.b) % P);
}
} a[maxn], s[maxn];
bool isr(int x) {
return !t[x].f || (t[t[x].f].ch[0] != x && t[t[x].f].ch[1] != x);
}
int wh(int x) {
return x == t[t[x].f].ch[1];
}
void upd(int x) {
s[x] = s[t[x].ch[0]] + a[x] + s[t[x].ch[1]];
}
void rotate(int x) {
int y = t[x].f, z = t[y].f, w = wh(x);
if(!isr(y)) {
t[z].ch[wh(y)] = x;
}
t[x].f = z;
t[t[x].ch[w ^ 1]].f = y;
t[y].ch[w] = t[x].ch[w ^ 1];
t[x].ch[w ^ 1] = y;
t[y].f = x;
upd(y);
upd(x);
}
void splay(int x) {
for(; !isr(x); rotate(x)) {
if(!isr(t[x].f)) {
rotate(wh(x) == wh(t[x].f) ? t[x].f : x);
}
}
}
void access(int x) {
for(int y = 0; x; y = x, x = t[x].f) {
splay(x);
t[x].ch[1] = y;
upd(x);
}
}
int fr(int x) {
access(x);
splay(x);
while(t[x].ch[0]) {
x = t[x].ch[0];
}
return x;
}
void link(int x, int y) {
if(!y) {
return;
}
if(fr(x) == fr(y)) {
access(x);
splay(x);
t[x].spf = y;
} else {
t[x].spf = 0;
access(x);
splay(x);
t[x].f = y;
}
}
void cut(int x, int y) {
if(t[x].spf == y) {
t[x].spf = 0;
} else {
access(x);
splay(x);
t[t[x].ch[0]].f = 0;
t[x].ch[0] = 0;
upd(x);
}
}
void exgcd(int a, int b, int &x, int &y) {
if(!b) {
x = 1;
y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
int query(int x) {
access(x);
splay(x);
data t1 = s[x];
int T = t[fr(x)].spf;
access(T);
splay(T);
data t2 = s[T];
int a, b;
if(t2.k == 1) {
return t2.b ? -1 : -2;
}
if(t2.k == 0) {
return (t1.k * t2.b + t1.b) % P;
}
exgcd(t2.k - 1, P, a, b);
return ((a * -t2.b % P + P) % P * t1.k % P + t1.b) % P;
}
} using lct::a; using lct::s; using lct::t;
int main() {
scanf("%d", &n);
a[0].k = s[0].k = 1;
for(int i = 1; i <= n; ++i) {
scanf("%d%d%d", &a[i].k, &f[i], &a[i].b);
s[i] = a[i];
}
for(int i = 1; i <= n; ++i) {
lct::link(i, f[i]);
}
scanf("%d", &m);
while(m--) {
int x, p, k, b;
scanf("%s", opt);
if(opt[0] == 'A') {
scanf("%d", &x);
printf("%d\n", lct::query(x));
} else {
scanf("%d%d%d%d", &x, &k, &p, &b);
lct::access(x);
lct::splay(x);
a[x] = lct::data(k, b);
lct::upd(x);
int T = x;
while(t[T].ch[0]) {
T = t[T].ch[0];
}
lct::cut(x, f[x]);
lct::link(T, t[T].spf);
f[x] = p;
lct::link(x, f[x]);
}
}
return 0;
}