滚回来学文化课了……
题目链接
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;
}