题面描述
思路
思考一下不难发现应该至少有一个环(没环貌似不能求解),也就是下面这样一个同余方程组
{
x
1
≡
k
1
∗
x
2
+
b
1
(
mod
10007
)
x
2
≡
k
2
∗
x
3
+
b
2
(
mod
10007
)
x
3
≡
k
3
∗
x
4
+
b
3
(
mod
10007
)
⋯
⋯
x
n
≡
k
n
∗
x
1
+
b
n
(
mod
10007
)
\begin{cases}x_1\equiv k_1*x_2+b_1(\operatorname{mod} 10007)\\x_2\equiv k_2*x_3+b_2(\operatorname{mod} 10007)\\x_3\equiv k_3*x_4+b_3(\operatorname{mod} 10007)\\\cdots\cdots \\x_n\equiv k_n*x_1+b_n(\operatorname{mod}10007)\end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x1≡k1∗x2+b1(mod10007)x2≡k2∗x3+b2(mod10007)x3≡k3∗x4+b3(mod10007)⋯⋯xn≡kn∗x1+bn(mod10007)
其中 x 1 , x 2 , x 3 , ⋯   , x n x_1,x_2,x_3,\cdots ,x_n x1,x2,x3,⋯,xn都可以表示成 x i ≡ ∏ k i x i + ∑ b x_i\equiv \prod k_i x_i+\sum b xi≡∏kixi+∑b的形式,例如 x 1 ≡ ∏ i = 1 n k i x 1 + ∑ i = 1 n ( b i ∗ ∏ j = 1 i − 1 k j ) x_1\equiv \prod\limits_{i=1}^nk_i x_1+\sum\limits_{i=1}^n(b_i*\prod\limits_{j=1}^{i-1} k_j) x1≡i=1∏nkix1+i=1∑n(bi∗j=1∏i−1kj)
经过观察可以发现,如果这个环断开一条边(一个同余方程),就成了一棵树,一个环,一棵树,构成一片森林(基环外向森林)。
接着开始了 LCT \operatorname{LCT} LCT。
断开这条边的起点(父),成为原树上的根(断开之后形成的根)的 s p e c i a l f a t h e r special\ father special father,简称 s f sf sf.
当我要把一个点调到辅助树根点,类似这样
那么此时
x i ≡ ∏ k i x i + ∑ b x_i\equiv \prod k_i x_i+\sum b xi≡∏kixi+∑b其中的 ∏ k i , ∑ b \prod k_i,\sum b ∏ki,∑b就可表示出来,也就是
struct data
{
int k,b;
data(){k=1,b=0;}
data(int k,int b):k(k),b(b){}
int sol(int x){return(k*x+b)%mod;}
data operator +(const data a)const
{
data c;
c.k=k*a.k%mod;
c.b=(b*a.k%mod+a.b)%mod;
return c;
}/*x1=k1*x2+b1 x2=k2*x1+b2 x1=k1*k2*x1+k1*b2+b1*/
}s[N],d[N];
void update(int p)
{s[p]=s[t[p].son[0]]+d[p]+s[t[p].son[1]];}//顺序不能变
/*严格遵循规律*/
如何解决询问:
int query(int x)
{
access(x);splay(x);
data s1=s[x];
int rtx=findroot(x),f=t[rtx].sf;
access(f);splay(f);
data s2=s[f];
if(s2.k==1)return s2.b?-1:-2;
if(s2.k==0)return s1.sol(s2.b);
int X,Y;
exgcd(s2.k-1,mod,X,Y);
return s1.sol((mod-X)%mod*s2.b%mod);
}
(
k
−
1
)
∗
x
+
b
i
≡
0
(
mod
10007
)
(k-1)*x+b_i\equiv0(\operatorname{mod}10007)
(k−1)∗x+bi≡0(mod10007)
(
k
−
1
)
∗
x
+
10007
∗
y
≡
−
b
i
(
mod
10007
)
(k-1)*x+10007*y\equiv-b_i(\operatorname{mod}10007)
(k−1)∗x+10007∗y≡−bi(mod10007)
打通 f − > r t x f->rtx f−>rtx的路径,就可以构成环。就可以求得 x f x_f xf的解,进而求到 x x x的解。
对于 k = 1 k=1 k=1,当且仅当 b = 0 b=0 b=0有无穷解,否则无解。
对于 k = 0 k=0 k=0, x = b x=b x=b。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define gc getchar()
using namespace std;
const int mod=10007;
const int N=3e4+10;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
struct data
{
int k,b;
data(){k=1,b=0;}
data(int k,int b):k(k),b(b){}
int sol(int x){return(k*x+b)%mod;}
data operator +(const data a)const
{
data c;
c.k=k*a.k%mod;
c.b=(b*a.k%mod+a.b)%mod;
return c;
}/*x1=k1*x2+b1 x2=k2*x1+b2 x1=k1*k2*x1+k1*b2+b1*/
};
int exgcd(int a,int b,int &x,int &y)
{
if(!b){x=1;y=0;return ;}
else{exgcd(b,a%b,y,x);y-=(a/b)*x;}
}
struct node{int f,son[2],sf;}t[N];//sf ->special father
data d[N],s[N];
inline bool nroot(int p){return t[t[p].f].son[0]==p||t[t[p].f].son[1]==p;}
void update(int p)
{s[p]=s[t[p].son[0]]+d[p]+s[t[p].son[1]];}
bool v[N],ins[N];//in_stack
void dfs(int x)
{
ins[x]=v[x]=1;
int f=t[x].f;
if(ins[f])//环
{
t[x].f=0;
t[x].sf=f;
}
if(!v[f])dfs(f);
ins[x]=0;
}
void rotate(int p,int w)
{
int f=t[p].f,gf=t[f].f;
int r=t[p].son[w],R=f;t[R].son[w^1]=r;if(r)t[r].f=R;
r=p;R=gf;if(nroot(f))t[R].son[t[R].son[1]==f]=r;t[r].f=R;
r=f;R=p;t[R].son[w]=r;t[r].f=R;update(f),update(p);
}
void splay(int p)
{
while(nroot(p))
{
int f=t[p].f,gf=t[f].f;
if(!nroot(f))rotate(p,t[f].son[0]==p);
else
{
if(t[f].son[0]==p&&t[gf].son[0]==f)rotate(f,1),rotate(p,1);
else if(t[f].son[0]==p&&t[gf].son[1]==f)rotate(p,1),rotate(p,0);
else if(t[f].son[1]==p&&t[gf].son[0]==f)rotate(p,0),rotate(p,1);
else rotate(f,0),rotate(p,0);
}
}
}
void access(int x)
{
for(int y=0;x;x=t[y=x].f)
splay(x),t[x].son[1]=y,update(x);
}
int findroot(int x)
{
access(x);splay(x);
while(t[x].son[0])x=t[x].son[0];
return x;
}
void link(int x,int y)
{
access(x);splay(x);t[x].f=y;
}
void cut(int x)
{
access(x);splay(x);
t[t[x].son[0]].f=0;
t[x].son[0]=0;
update(x);
}
int query(int x)
{
access(x);splay(x);
data s1=s[x];
int rtx=findroot(x),f=t[rtx].sf;
access(f);splay(f);
data s2=s[f];
if(s2.k==1)return s2.b?-1:-2;
if(s2.k==0)return s1.sol(s2.b);
int X,Y;
exgcd(s2.k-1,mod,X,Y);
return s1.sol((mod-X)%mod*s2.b%mod);
}
bool check(int x,int rtx)//is_in_circle?
{
int y=t[rtx].sf;
if(x==y)return 1;
access(y);splay(y);splay(x);
return nroot(y);
}
void change(int x,int y,int k,int b)
{
access(x);splay(x);d[x]=data(k,b);update(x);
int rtx=findroot(x);
if(x==rtx)
{
int rty=findroot(y);
if(rty==x)t[x].sf=y;//in_circle
else t[x].sf=0,link(x,y);//out
}
else
{
if(check(x,rtx))
{
cut(x);link(rtx,t[rtx].sf);
t[rtx].sf=0;
int rty=findroot(y);
if(rty==x)t[x].sf=y;
else link(x,y);
}
else
{
cut(x);
int rty=findroot(y);
if(rty==x)t[x].sf=y;
else link(x,y);
}
}
}
int main()
{
int n;qr(n);
for(int i=1;i<=n;i++)
{
int k,b;qr(k),qr(t[i].f),qr(b);
d[i]=s[i]=data(k,b);
}
for(int i=1;i<=n;i++)if(!v[i])dfs(i);//建基环森林
int m;qr(m);
while(m--)
{
int x,k,b,f;
char s[3];scanf("%s%d",s+1,&x);
if(s[1]=='A')qw(query(x)),puts("");
else
{
qr(k),qr(f),qr(b);
change(x,f,k,b);
}
}
return 0;
}