题目大意
给出
n
个变量
- 解出
xi 的值,或输出无解或无穷解- 将第
i
个方程改为
xi=k′ixj′+b′i(mod10007) n<30000,m<100000
分析
这道题还是比较显然的。
我们发现每个变量都依赖于另一个变量的值。那么他们之间连边以后必定形成若干个环套树,且边都是有向的。
不妨用LCT来维护这个图。
从某个点 x 出发,一直走必定是一个ρ 型。那么我们就可以解出那个环接入点的变量的值,从而算出 x 的值。
沿着这个思路,我们用LCT来维护一条链。而链顶连回这条链中的某个点,我们需要记录一下链顶连到的是哪个点,而且这个信息是和LCT的部分没有任何关系的。
维护的部分,沿着一定的顺序一一合并两棵子树的信息就可以了。
我的写法里面定义了如此几个函数:getself(x) 计算了 x 这个变量的值,前提是x 是接入点。具体是 access(x) 以后,解一个同余方程就可以了。由此也可见,我是将一棵环套树上面的环剖开了,无视某条边来进行维护。
gettail(x) 返回的是从 x 这个点开始向上跳达到的链顶。
query(x) 是计算任意变量 x 的值。具体是getself(gettail(x)) 以后再 access(x) 并计算。isancestor(x,y) 返回 x 是不是
y 的某个祖先,具体来说是 access(y) 后 splay(x) 再判 x 是不是y 的右儿子。change(x) 这个函数是改变 x 这个变量的信息。这里要分成两种情况来处理,分别是
x 在环上,那么此时的接入点就要被修改了。-
x
不在环上,那么原来的环就不会被影响,
link 一下 x 就好了。
还有预处理部分需要判一下
isancestor 再去决定是应该 link 还是设为接入点。至此,这个问题就基本上解决了。
时间复杂度 O(mlogn)以下贴一下代码。
#include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> #include <utility> #include <cstring> #include <bitset> #include <string> #include <vector> #include <queue> #include <map> #include <set> typedef double db; typedef long long LL; typedef std :: pair< int, int > PII; typedef std :: pair< LL, LL > PLL; typedef std :: pair< db, db > PDD; const db dInf = 1E90; const LL lInf = ( LL ) 1E16; const int Inf = 0x23333333; const int N = 30005, Mo = 10007; #define it iterator #define rbg rbegin() #define ren rend() #define bg begin() #define en end() #define sz size() #define fdi( i, x ) for ( typeof( x.rbg ) i=x.rbg; i!=x.ren; ++i ) #define foi( i, x ) for ( typeof( x.bg ) i=x.bg; i!=x.en; ++i ) #define fd( i, y, x ) for ( int i=( y )-1, lim=x; i>=lim; --i ) #define fo( i, x, y ) for ( int i=x, lim=y; i<lim; ++i ) #define mkp( A, B ) make_pair( A, B ) #define pub( x ) push_back( x ) #define pob( x ) pop_back( x ) #define puf( x ) push_front( x ) #define pof( x ) pop_front( x ) #define fi first #define se second inline int pwr( const int &x, const int &p ) { if ( !p ) return 1; int temp = pwr( x, p >> 1 ); temp = temp * temp % Mo; if ( p & 1 ) temp = temp * x % Mo; return temp; } int gcd( const int A, const int B ) { return ( B ? gcd( B, A % B ) : A ); } namespace LCT { struct node { int fa, s[2]; int _k, _b, k, b; } a[N]; int grpfa[N]; inline void update( const int &x ) { a[x]._k = a[x].k, a[x]._b = a[x].b; const int &l = a[x].s[0], &r = a[x].s[1]; if ( l ) { a[x]._k = ( a[x]._k * a[l]._k ) % Mo; a[x]._b = ( a[l]._k * a[x]._b + a[l]._b ) % Mo; } if ( r ) { a[x]._b = ( a[x]._k * a[r]._b + a[x]._b ) % Mo; a[x]._k = ( a[x]._k * a[r]._k ) % Mo; } } inline bool top( const int &x ) { const int &y = a[x].fa; return ( !y ) || a[y].s[0]!=x && a[y].s[1]!=x; } inline int dir( const int &x ) { const int &y = a[x].fa; return a[y].s[1] == x; } inline void rotate( const int &x ) { int y = a[x].fa, z = a[y].fa; bool p = dir( x ), q = p ^ 1; int A = a[x].s[q]; if ( !top( y ) ) a[z].s[ dir( y ) ] = x; a[y].s[p] = A, a[y].fa = x; a[x].s[q] = y, a[x].fa = z; if ( A ) a[A].fa = y; update( y ); } inline void splay( const int &x ) { while ( !top( x ) ) { int y = a[x].fa, z = a[y].fa; if ( top( y ) ) rotate( x ); else if ( top( z ) || dir( y )^dir( x ) ) rotate( x ), rotate( x ); else rotate( y ), rotate( x ); } update( x ); } inline void access( const int &x ) { for ( int _x=x, y=0; _x; _x=a[_x].fa ) splay( _x ), a[_x].s[0] = y, y = _x; splay( x ); } inline int getself( const int &x ) { access( x ); int k = ( 1 - a[x]._k + Mo ) % Mo, b = a[x]._b; if ( gcd( k, Mo )!=1 ) return ( b ? -1 : -2 ); else return b * pwr( k, Mo - 2 ) % Mo; } inline int gettail( const int &x ) { int _x = x; access( x ); for ( ; a[_x].s[1]; _x=a[_x].s[1] ); splay( _x ); return _x; } inline int query( const int &x ) { int core = getself( grpfa[ gettail( x ) ] ); if ( core < 0 ) return core; access( x ); return ( a[x]._k * core + a[x]._b ) % Mo; } inline bool isancestor( const int &x, const int &y ) { if ( x==y ) return 1; access( y ), splay( x ); return a[x].s[0] == y; } inline void change( const int &x, const int &_y, const int &k, const int &b ) { int tail = gettail( x ); bool inloop = isancestor( x, grpfa[tail] ); access( x ), a[x].s[1] = a[ a[x].s[1] ].fa = 0; if ( inloop ) { access( tail ); a[tail].fa = grpfa[tail], grpfa[tail] = 0; } a[x].fa = 0; if ( isancestor( x, _y ) ) grpfa[x] = _y; else a[x].fa = _y; a[x].k = k, a[x].b = b, access( x ); } } int n; void preprocessing() { int fa; scanf( "%d", &n ), ++n; fo ( i, 1, n ) { scanf( "%d%d%d", &LCT :: a[i].k, &fa, &LCT :: a[i].b ); if ( LCT :: isancestor( i, fa ) ) LCT :: grpfa[i] = fa; else LCT :: a[i].fa = fa; } } void solve() { char type; int T, x, y, k, b; scanf( "%d", &T ); fo ( Case, 0, T ) { for ( type='`'; type!='A' && type!='C'; type=getchar() ); if ( type=='A' ) { scanf( "%d", &x ); printf( "%d\n", LCT :: query( x ) ); } else { scanf( "%d%d%d%d", &x, &k, &y, &b ); LCT :: change( x, y, k, b ); } } } int main() { preprocessing(); solve(); return 0; }
- 将第
i
个方程改为