题解
真·动态树好题。
根据题目要求,我们以点i向其p[i]连边,必然会得到基环树林,每个解可以在所在环里得解。我们将每个环上的一条边连成虚边,该边所连接的就是LCT里的root和p[root](记为rt的spf(special_father))。
我们在update是可以维护每个点的k,b,不断向上累计系数,更新到rt.
在求当前a的值时候,我们可以先找到rt,把rt的spf access+splay绕到顶点,此时取出rt_spf所记录的k,b系数,设root的值为x,可得方程
。所以若
,则有无穷解,若
。
对于修改操作,若a不为root,先把a和f切掉,看rt_spf和rt还在不在同一颗树上,不在了就把root_spf变成root_f,因为现在a所在的环从a断开了,否则直接切掉a。然后看a的修改后p在不在同一颗树内,在就a access+splay 然后a_spf连接p[a],否则连f。
代码
膜了一发PO姐的代码,感觉指针写起来莫名爽快。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#define mod 10007
#define gc getchar
using namespace std;
const int N=3e4+10;
int fa[N],n,m,v[N],cnt;
char o[10];
inline int rd()
{
char ch=gc();int x=0,f=1;
while(!isdigit(ch)){if(ch=='-') f=-1;ch=gc();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=gc();}
return x*f;
}
struct line{
int k,b;
line operator +(const line &u)const{
return (line){k*u.k%mod,(u.k*b%mod+u.b)%mod};
}
int F (int x){return (k*x+b)%mod;}
};
struct Node{
Node *ls,*rs,*f,*sf;
line num,sum;
Node(int k,int b);
void pushup();
}*null= new Node(1,0),*tree[N];
Node :: Node(int k,int b)
{
ls=rs=f=sf=null;
num.k=sum.k=k;
num.b=sum.b=b;
}
void Node :: pushup()
{sum=ls->sum+num+rs->sum;}
void dfs(int x)
{
v[x]=cnt;
if(v[fa[x]]==cnt){
tree[x]->sf=tree[fa[x]];
return;
}
tree[x]->f=tree[fa[x]];
if(!v[fa[x]]) dfs(fa[x]);
}
void Zig(Node *x)
{
Node *y=x->f;Node *z=y->f;
y->ls=x->rs;x->rs->f=y;x->rs=y;y->f=x;x->f=z;
if(z->ls==y) z->ls=x;else if(z->rs==y) z->rs=x;
y->pushup();
}
void Zag(Node *x)
{
Node* y=x->f;Node* z=y->f;
y->rs=x->ls;x->ls->f=y;x->ls=y;y->f=x;x->f=z;
if(z->ls==y) z->ls=x;else if(z->rs==y) z->rs=x;
y->pushup();
}
void splay(Node *x)
{
Node *y,*z;
while((x->f->ls==x)||(x->f->rs==x)){
y=x->f;z=y->f;
if(y->ls==x){
if(z->ls==y) Zig(y);
Zig(x);
}else{
if(z->rs==y) Zag(y);
Zag(x);
}
}
x->pushup();
}
inline void access(Node *x)
{
Node *u=null;
for(;x!=null;x=x->f){
splay(x);
x->rs=u;
x->pushup();
u=x;
}
}
Node* fdrt(Node *x)
{
access(x);splay(x);Node *u=x;
for(;u->ls!=null;u=u->ls);
return u;
}
pair<int,int>exgcd(int x,int y)
{
if(!y) return make_pair(1,0);
pair<int,int>ret=exgcd(y,x%y);
return make_pair(ret.second,ret.first-x/y*ret.second);
}
inline int inv(int x)
{return (exgcd((x%mod+mod)%mod,mod).first%mod+mod)%mod;}
int query(Node *x)
{
Node *rt=fdrt(x);
access(rt->sf);splay(rt->sf);
int K=rt->sf->sum.k,B=rt->sf->sum.b;
if(K==1){
if(B==0) return -2;
else return -1;
}
int ret=(mod-B)*inv(K-1)%mod;
access(x);splay(x);
return x->sum.F(ret);
}
void modify(Node *x,Node *y,int k,int b)
{
Node* rt=fdrt(x);
x->num.k=k;x->num.b=b;x->pushup();
if(rt==x) x->sf=null;
else{
access(x);splay(x);
x->ls->f=null;x->ls=null;x->pushup();
if(fdrt(rt->sf)!=rt){
access(rt);splay(rt);
rt->f=rt->sf;rt->sf=null;
}
}
access(x);splay(x);
if(fdrt(y)!=x) x->f=y;
else x->sf=y;
}
int main(){
int i,j,k,p,a,b;
n=rd();
for(i=1;i<=n;++i){
k=rd();fa[i]=rd();b=rd();
tree[i]= new Node(k,b);
}
for(i=1;i<=n;++i) if(!v[i]) {cnt++;dfs(i);}
m=rd();
while(m--){
scanf("%s",o);
if(o[0]=='A'){a=rd();printf("%d\n",query(tree[a]));}
else{a=rd();k=rd();p=rd();b=rd();modify(tree[a],tree[p],k,b);}
}
}