1 条题解
-
0
自动搬运
来自洛谷,原作者为

luanyanjia
菜 -我ら是个と大に傻む逼なり-搬运于
2025-08-24 23:00:02,当前版本为作者最后更新于2024-08-19 08:23:08,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
从题目名字看出此题需要用动态树解决。对于任意 ,都有唯一的 与之对应,由 向 连边, 种关系显然构成一基环树森林。对于环上的节点,一个点可以自己表示自己,所以可以直接解出该点的权值,其他点从环上的点直接推出即可。
考虑如何动态维护这个过程,一个点上对应的线性变换显然可以用矩阵刻画(其实只是不想动脑子),对于一棵基环树,我们把它多出来那一条边,和根节点的答案都存在根节点上(这样的话换根就要慎重一些了),询问时直接链乘积求出系数即可。
对于任意 操作,若 不连通则直接连边(注意此处 也没有影响,因为能连出边的点一定不属于一棵基环树)。否则算出 的答案,并把答案和这条边存在 上。
修改的时候,设此处原来的边为 ,现换为 。那么我们先 (此处根节点需要特判,因为它连向父亲的边没有真实连上),然后 ,最后如果 不是根节点的话,要把 所属的基环树的那条虚边再 一遍(因为修改后环可能被拆了,此时应该将它真实连上以保证正确性)。
最后关于无解和多解。可以证明,如果根无解,那么整棵树所有节点都无解,多解也有一样的性质。
#include<bits/stdc++.h> using namespace std; inline void rd(){} template<typename T,typename ...U> inline void rd(T &x,U &...args){ char ch=getchar(); T f=1;x=0; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x*=f;rd(args...); } const int N=3e4+5,mod=10007; struct Matrix{ int m[2][2]; Matrix(){memset(m,0,sizeof m);} Matrix(int _x){memset(m,0,sizeof m);m[0][0]=m[1][1]=_x;} Matrix friend operator+(Matrix a,Matrix b){ Matrix c; for(int i=0;i<=1;i++) for(int j=0;j<=1;j++)c.m[i][j]=(a.m[i][j]+b.m[i][j])%mod; return c; } Matrix friend operator*(Matrix a,Matrix b){ Matrix c; for(int i=0;i<=1;i++) for(int j=0;j<=1;j++) for(int k=0;k<=1;k++)(c.m[i][j]+=a.m[i][k]*b.m[k][j])%=mod; return c; } }; inline int KSM(int x,int n){ int ans=1; while(n){ if(n&1)ans=ans*x%mod; x=x*x%mod; n>>=1; } return ans; } int n,q; namespace LCT{ int f[N],ch[N][2],tag[N]; Matrix m[N],prd[N]; struct{int x,y,ans;}nd[N]; #define ls ch[p][0] #define rs ch[p][1] inline void PushUp(int p){prd[p]=prd[ls]*m[p]*prd[rs];} inline void Rev(int p){ tag[p]^=1;swap(ls,rs); PushUp(p); } inline void PushDown(int p){ if(!tag[p])return ; Rev(ls),Rev(rs);tag[p]=0; } inline int Get(int p){return ch[f[p]][1]==p;} inline int IsRoot(int p){return ch[f[p]][1]!=p&&ch[f[p]][0]!=p;} void Update(int p){ if(!IsRoot(p))Update(f[p]); PushDown(p); } inline void Rotate(int x){ int y=f[x],z=f[y],k=Get(x); if(!IsRoot(y))ch[z][Get(y)]=x; ch[y][k]=ch[x][!k],ch[x][!k]=y; f[y]=x,f[x]=z,f[ch[y][k]]=y; PushUp(y),PushUp(x); } inline void Splay(int x){ Update(x); for(int fa=f[x];!IsRoot(x);Rotate(x),fa=f[x]) if(!IsRoot(fa))Rotate(Get(fa)==Get(x)?fa:x); } inline int Access(int x){ int p; for(p=0;x;p=x,x=f[x]) Splay(x),ch[x][1]=p,PushUp(x); return p; } inline void MakeRoot(int x){ x=Access(x);Rev(x); } inline int FindRoot(int p){ p=Access(p); while(ls)p=ls,PushDown(p); return Splay(p),p; } inline void Link(int x,int y){ if(FindRoot(x)==FindRoot(y)){ MakeRoot(x);Access(y); Splay(x);Matrix mm=prd[ch[x][1]]*m[x]; nd[x].x=x,nd[x].y=y; int k=(mm.m[0][0]+mod-1)%mod,b=mod-mm.m[1][0]; if(k==0&&b==0)nd[x].ans=-2; else if(k==0)nd[x].ans=-1; else nd[x].ans=1ll*b*KSM(k,mod-2)%mod; }else{ MakeRoot(x); Splay(x);f[x]=y; } } inline void Modify(int x,int k,int y,int b){ int rt=FindRoot(x); Splay(x); m[x].m[0][0]=k,m[x].m[1][0]=b; PushUp(x); if(rt!=x){ Access(x);Splay(x); f[ch[x][0]]=0,ch[x][0]=0; Link(x,y); Link(nd[rt].x,nd[rt].y); } else Link(x,y); } inline int Query(int p){ int rt=FindRoot(p);Access(p); Splay(rt); int k=prd[ch[rt][1]].m[0][0],b=prd[ch[rt][1]].m[1][0]; if(nd[rt].ans==-1)return -1; if(nd[rt].ans==-2)return -2; return (1ll*k*nd[rt].ans%mod+b)%mod; } #undef ls #undef rs } int p[N]; using namespace LCT; signed main(){ rd(n); prd[0]=m[0]=Matrix(1); for(int i=1;i<=n;i++){ int k,b;rd(k,p[i],b); m[i].m[0][0]=k; m[i].m[1][0]=b; m[i].m[1][1]=1; } for(int i=1;i<=n;i++)Link(i,p[i]); rd(q); while(q--){ char s[3];int a,x,y,z; scanf("%s",s); if(s[0]=='A'){ rd(a); printf("%d\n",Query(a)); }else if(s[0]=='C'){ rd(a,x,y,z); Modify(a,x,y,z); } } return 0; }
- 1
信息
- ID
- 10454
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者