BZOJ2759 一个动态树好题 LCT
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ2759
题意概括
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%
题解
这题不大会,基本上是抄的……
rev标记不用打,大概是因为不用link和cut吧。
大佬题解:
http://blog.csdn.net/qq_30401759/article/details/50649672
代码
#include <cstring> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cmath> using namespace std; const int N=30005,Mod=10007; struct fc{ int k,b; fc (){k=1,b=0;} fc (int k_,int b_){k=k_,b=b_;} int calc(int x){ return (k*x+b)%Mod; } }; fc operator + (fc a,fc b){ return fc(a.k*b.k%Mod,(b.k*a.b+b.b)%Mod); } int Pow(int x,int y){ if (y==0) return 1; int xx=Pow(x,y/2); xx=xx*xx%Mod; if (y&1) xx=xx*x%Mod; return xx; } int Inv(int a){ return Pow(a%Mod,Mod-2); } int fa[N],son[N][2],sfa[N]; fc val[N],sum[N]; bool isroot(int x){ return son[fa[x]][0]!=x&&son[fa[x]][1]!=x; } void pushup(int x){ sum[x]=sum[son[x][0]]+val[x]+sum[son[x][1]]; } int wson(int x){ return son[fa[x]][1]==x; } void rotate(int x){ if (isroot(x)) return; int y=fa[x],z=fa[y],L=wson(x),R=L^1; if (!isroot(y)) son[z][wson(y)]=x; fa[x]=z,fa[y]=x,fa[son[x][R]]=y; son[y][L]=son[x][R],son[x][R]=y; pushup(y),pushup(x); } void splay(int x){ for (int y=fa[x];!isroot(x);rotate(x),y=fa[x]) if (!isroot(y)) rotate(wson(x)==wson(y)?y:x); } void access(int x){ for (int t=0;x;t=x,x=fa[x]){ splay(x); son[x][1]=t; pushup(x); } } void link(int x,int y){ access(x); splay(x); fa[x]=y; } void cut(int x){ access(x); splay(x); fa[son[x][0]]=0; son[x][0]=0; pushup(x); } int find(int x){ access(x); splay(x); while (son[x][0]) x=son[x][0]; splay(x); return x; } int query(int x){ access(x); splay(x); fc a=sum[x]; int rt=find(x),spfa=sfa[rt];//不是SPFA,是special_father access(spfa); splay(spfa); fc b=sum[spfa]; // X[x]=a.k * X[rt] + a.b if (b.k==1) return b.b?-1:-2; if (b.k==0) return a.calc(b.b); // x*(b.k-1) + b.b = 0 (mod Mod) // x = Inv(1-b.k) * b.b return a.calc(Inv(1-b.k+Mod)*b.b%Mod); } int oncirclr(int x,int rt){ int f=sfa[rt]; if (x==f) return 1; access(f); splay(f); splay(x); return !isroot(f); } void update(int x,int p,int k,int b){ access(x); splay(x); val[x]=fc(k,b); pushup(x); int rt=find(x); if (x==rt){ int prt=find(p); if (prt==rt) sfa[x]=p; else sfa[x]=0,link(x,p); } else if (oncirclr(x,rt)){ cut(x); link(rt,sfa[rt]); sfa[rt]=0; int prt=find(p); if (prt==x) sfa[x]=p; else link(x,p); } else { cut(x); int prt=find(p); if (prt==x) sfa[x]=p; else link(x,p); } } int vis[N],in[N]; void dfs(int x){ in[x]=vis[x]=1; int y=fa[x]; if (in[y]){ fa[x]=0; sfa[x]=y; } if (!vis[y]) dfs(y); in[x]=0; } int n,m; int main(){ scanf("%d",&n); for (int i=1;i<=n;i++){ int k,b; scanf("%d%d%d",&k,&fa[i],&b); val[i]=sum[i]=fc(k,b); son[i][0]=son[i][1]=sfa[i]=0; } memset(vis,0,sizeof vis); memset(in,0,sizeof in); for (int i=1;i<=n;i++) if (!vis[i]) dfs(i); scanf("%d",&m); for (int i=1;i<=m;i++){ char op[4]; scanf("%s",op); if (op[0]=='A'){ int x; scanf("%d",&x); printf("%d\n",query(x)); } else { int x,y,k,b; scanf("%d%d%d%d",&x,&k,&y,&b); update(x,y,k,b); } } return 0; }