Description
有N个未知数x[1..n]和N个等式组成的同余方程组:
x[i]=k[i]*x[p[i]]+b[i] mod 10007
其中,k[i],b[i],x[i]∈[0,10007)∩Z
你要应付Q个事务,每个是两种情况之一:
一.询问当前x[a]的解
A a
无解输出-1
x[a]有多解输出-2
否则输出x[a]
二.修改一个等式
C a k[a] p[a] b[a]
Input
N
下面N行,每行三个整数k[i] p[i] b[i]
Q
下面Q行,每行一个事务,格式见题目描述
Output
对每个询问,输出一行一个整数。
对100%的数据,1≤N≤30000,0≤Q≤100000,时限2秒,其中询问事务约占总数的80%
Sample Input
2 2 1
2 3 2
2 4 3
2 5 4
2 3 5
5
A 1
A 2
C 5 3 1 1
A 4
A 5
Sample Output
7141
4256
2126
分析:因为删错了边被这题卡了整整一天,还是在看了题解的情况下,思路还是蛮神奇的,
可以看出原图中每个联通分量都是一个环套树,然后我们把环上一边拆掉然后用动态树维
护,因为是有向图,所以这棵树不能换根,我是在动态树分类下找到这道题的,但是一直
想不出怎么用动态树维护这种东西,因为印象里平衡树都是通过updata合并两个儿子的属
性来更新自己的值,而这题很明显边是要从儿子指向父亲的,这怎么维护呢。。。
然后神奇的思路是,我们不需要对平衡树中的每一个点都去直接维护它的值,我们只需要
维护最后一个点就够了,因为动态树的access操作可以随意把一个点变成这条链splay中的
最后一点,于是我们可以这样合并:sum[u] = sum[ch[u][0]] + value[u] + sum[ch[u][1]]每次都
把左边的都并入右边的,这样根节点的值就能表示这条链中最后一个点的值了(类似中序
遍历), 然后我们继续把环上任意一边删去,将其中一点作为根节点,剩下的点作为一个
special father,这样我们access(sp)后就能得到sp自己的表示方法,然后通过讨论k和b的
值来确定有没有解或者多解的情况,这样就解决了查询问题,然后考虑修改操作,比较麻
烦,如果要改的点是一个root,那么直接修改sp就行了,否则我们要看要修改点是否在环
上,若在环上需要删边后先将root指向sp的边加进去,然后看是否会出现新环,有就讲新
父亲作为sp,否则直接连虚边。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#define INF 2147483640
#define eps 1e-9
#define MAXN 30010
#define P 10007
using namespace std;
int n,q,ki,bi,fa[MAXN],inv[MAXN],pi[MAXN],sp[MAXN],ch[MAXN][2];
bool vis[MAXN],cir[MAXN];
char op[3];
int get()
{
char ch;while (!isdigit(ch=getchar()));
int o=ch-'0';while (isdigit(ch=getchar())) o=o*10+ch-'0';
return o;
}
struct data
{
int k,b;
data() { k = 1;b = 0;}
data(int x,int y) {k = x;b = y;}
}value[MAXN],sum[MAXN];
data operator * (data a,data b)
{
return data(a.k*b.k % P,(a.b*b.k + b.b) % P);
}
int ksm(int a,int b)
{
int ans = 1;
while(b)
{
if(b & 1) ans = ans * a % P;
a = a * a % P;
b >>= 1;
}
return ans;
}
inline bool isroot(int x)
{
return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}
inline int findroot(int x)
{
while(ch[x][0]) x = ch[x][0];
return x;
}
void push_up(int x)
{
sum[x] = sum[ch[x][0]] * value[x] * sum[ch[x][1]];
}
void rotate(int x)
{
int y = fa[x],z = fa[y];
int d = ch[y][0] == x ? 0 : 1;
if(!isroot(y))
{
if(ch[z][0] == y) ch[z][0] = x;
else ch[z][1] = x;
}
fa[y] = x,fa[x] = z,fa[ch[x][d^1]] = y;
ch[y][d] = ch[x][d^1],ch[x][d^1] = y;
push_up(y),push_up(x);
}
void splay(int x)
{
while(!isroot(x))
{
int y = fa[x],z = fa[y];
if(!isroot(y))
{
if((ch[z][0] == y) ^ (ch[y][0] == x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
int t = 0;
while(x)
{
splay(x);
ch[x][1] = t;
push_up(x);
t = x,x = fa[x];
}
}
void dfs(int u)
{
cir[u] = vis[u] = true;
if(cir[fa[u]])
{
sp[u] = fa[u];
fa[u] = 0;
}
if(!vis[fa[u]]) dfs(fa[u]);
cir[u] = false;
}
int query(int x)
{
access(x);
splay(x);
data tem = sum[x];
int root = findroot(x),sfa = sp[root];
access(sfa);
splay(sfa);
data temp = sum[sfa];
if(temp.k == 1 && temp.b) return -1;
if(temp.k == 1 && !temp.b) return -2;
int val = temp.k ? (P-temp.b) * inv[temp.k-1] % P : temp.b;
return (tem.k*val + tem.b) % P;
}
void change()
{
int t = get(),kt = get(),pt = get(),bt = get();
access(t);
splay(t);
value[t] = data(kt,bt);
push_up(t);
int root = findroot(t);
if(root == t)
{
access(pt);
splay(pt);
int ptroot = findroot(pt);
if(ptroot == t) sp[t] = pt;
else
{
fa[t] = pt;
sp[t] = 0;
}
}
else
{
splay(pi[t]);
fa[t] = ch[pi[t]][1] = 0;
push_up(pi[t]);
access(sp[root]);
splay(sp[root]);
if(findroot(sp[root]) != root)
{
fa[pi[t]] = sp[root];
sp[root] = 0;
}
access(pt);
splay(pt);
int rootpt = findroot(pt);
if(rootpt == t) sp[t] = pt;
else
{
splay(t);
fa[t] = pt;
}
}
pi[t] = pt;
}
int main()
{
for(int i = 1;i < P;i++) inv[i] = ksm(i,P-2);
n = get();
for(int i = 1;i <= n;i++)
{
ki = get(),pi[i] = get(),bi = get();
value[i] = data(ki,bi);
fa[i] = pi[i];
}
for(int i = 1;i <= n;i++)
if(!vis[i]) dfs(i);
q = get();
for(int i = 1;i <= q;i++)
{
scanf("%s",op);
if(op[0] == 'A')
{
int x = get();
printf("%d\n",query(x));
}
else change();
}
}