滚回来学文化课了……

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2759

题解

LCT,显然的做法是维护链上所有一次函数的复合。
如何处理根的问题?

考虑所有的连通块都建成有根树,另外记录每个根的父亲。
修改父亲的时候,如果修改的是根,那么要么直接改,要么合并两个连通块,根变为非根;如果修改的不是根,要特判分裂了两个连通块导致根的父亲进了新的连通块的情况,如果如此则需重新合并,根变为非根,其余直接改即可。

时间复杂度\(O(n\log n)\).

代码

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
using namespace std;

void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

const int N = 3e4;
const int P = 1e4+7;
int inv[P+2];
struct Data
{
	int a,b;
	Data() {}
	Data(int _a,int _b) {a = _a,b = _b;}
	Data operator *(const Data &arg) const {return Data(a*arg.a%P,(b*arg.a+arg.b)%P);}
	int calc(int x) {return (a*x+b)%P;}
	int solve()
	{
		if(a==0) {return b==0?-2:-1;}
		return inv[a]*(P-b)%P;
	}
};
int fa[N+3];
int uf[N+3];
int n,q;

int findfa(int u)
{
	int i = u;
	while(u!=uf[u]) {u = uf[u];}
	while(u!=uf[i])
	{
		int j = uf[i]; uf[i] = u; i = j;
	}
	return u;
}

struct SplayNode
{
	int son[2],fa; Data val,sum;
} spl[N+3];
bool isroot(int u) {return spl[spl[u].fa].son[0]!=u && spl[spl[u].fa].son[1]!=u;}
void pushup(int u)
{
	int ls = spl[u].son[0],rs = spl[u].son[1];
	spl[u].sum = spl[u].val;
	if(ls) {spl[u].sum = spl[ls].sum*spl[u].sum;}
	if(rs) {spl[u].sum = spl[u].sum*spl[rs].sum;}
}
void rotate(int u)
{
	int x = spl[u].fa,y = spl[x].fa,dir = u==spl[x].son[0];
	if(!isroot(x)) {spl[y].son[x==spl[y].son[1]] = u;}
	spl[u].fa = y;
	spl[x].son[dir^1] = spl[u].son[dir];
	if(spl[u].son[dir]) {spl[spl[u].son[dir]].fa = x;}
	spl[u].son[dir] = x; spl[x].fa = u;
	pushup(x);
}
void splaynode(int u)
{
	int x = u;
	while(!isroot(x))
	{
		x = spl[x].fa;
	}
	while(!isroot(u))
	{
		int y = spl[u].fa,z = spl[y].fa;
		if(!isroot(y)) {(u==spl[y].son[1])^(y==spl[z].son[1]) ? rotate(u) : rotate(y);}
		rotate(u);
	}
	pushup(u);
}
void access(int u)
{
	for(int i=0; u; i=u,u=spl[u].fa)
	{
		splaynode(u);
		spl[u].son[1] = i;
		pushup(u);
	}
}
int findroot(int u,int flg=0)
{
	access(u); splaynode(u);
	while(spl[u].son[0]) u = spl[u].son[0];
	if(flg) splaynode(u);
	return u;
}
void link(int u,int v) //fa[u]=v
{
//	printf("link %d %d\n",u,v);
	access(u); splaynode(u);
	spl[u].fa = v;
}
void cut(int u) //fa[u]=v
{
//	printf("cut %d\n",u);
	access(u); splaynode(u);
	int v = spl[u].son[0]; spl[u].son[0] = spl[v].fa = 0;
	pushup(u);
}
void modify(int u,Data x)
{
	splaynode(u);
	spl[u].val = x;
}

int main()
{
	inv[1] = 1; for(int i=2; i<P; i++) inv[i] = P-(P/i*inv[P%i]%P);
	scanf("%d",&n);
	for(int i=1; i<=n; i++) uf[i] = i;
	for(int i=1; i<=n; i++)
	{
		int u,x,y; scanf("%d%d%d",&x,&u,&y);
		spl[i].val = spl[i].sum = Data(x,y);
		int uu = findfa(u);
		if(uu==i)
		{
			fa[i] = u;
		}
		else
		{
			link(i,u);
			uf[findfa(i)] = uu;
		}
	}
	scanf("%d",&q);
	while(q--)
	{
		char opt[5]; scanf("%s",opt+1);
		if(opt[1]=='A')
		{
			int u; scanf("%d",&u);
			int rt = findroot(u);
			access(fa[rt]); splaynode(fa[rt]);
			int x = Data((spl[fa[rt]].sum.a-1+P)%P,spl[fa[rt]].sum.b).solve();
			if(x<0) {printf("%d\n",x);}
			else
			{
				access(u); splaynode(u);
				int ans = spl[u].sum.calc(x);
				printf("%d\n",ans);
			}
		}
		else if(opt[1]=='C')
		{
			int u,ax,ay,v; scanf("%d%d%d%d",&u,&ax,&v,&ay);
			modify(u,Data(ax,ay));
			if(fa[u])
			{
				int rtv = findroot(v);
				if(rtv==u) {fa[u] = v;}
				else
				{
					fa[u] = 0;
					link(u,v);
				}
			}
			else
			{
				int rt = findroot(u);
				cut(u);
				int rtf = findroot(fa[rt]);
				if(rtf==u)
				{
					link(rt,fa[rt]);
					fa[rt] = 0;
				}
				int rtv = findroot(v);
				if(rtv==u) {fa[u] = v;}
				else {link(u,v);}
			}
		}
	}
	return 0;
}