BZOJ2759: 一个动态树好题
n<=30000个同余方程:$x_i\equiv k_i*x_{p_i}+b_i (mod 10007)$。m<=100000个操作:一、修改某个不等式的$k_i,p_i,b_i$,二、查询某个变量的值。无解-1,无穷解-2.
极其好玩的一道题。不像某些“绝世好题”实际是水题。。
首先按依赖关系可以建成基环树啦,因为n个点,每个点1条出边嘛。
错误!是基环森林。因为忽略了这个,所以本地找别人代码对拍时造数据也是造成一棵基环树,查了将近5h才发现这回事。。
很好。
要求解的话,肯定先从那个环入手,环上算出某个点的值,然后一路推下去即可。可以先列个简单点的东西:如果有同余方程组
$x_1\equiv k_1*x_{2}+b_1$
$x_2\equiv k_2*x_{3}+b_2$
......
$x_n\equiv k_n*x_{1}+b_n$
乱搞+不完全归纳+YY+找规律可得:$x_1=\prod_{i=1}^{n}k_i x_1+\sum_{i=1}^{n}b_i\prod_{j=1}^{i-1}k_j$。这两坨系数可以用可合并的数据结构维护。
那写到这里自然会选择LCT啦(因为题目说的)。
首先基环树的常见套路:不换根,然后在根节点(有向图,这个所谓的根节点一定在环上)那里存一个东西记基环树比普通树多出来的那条边。我把他叫做$biu$,因为他就是突然出现的,就有一种$biu$的感觉,是不是很生动啊!那相应的$cut$和$link$函数也要改改,如果要把$x$和其父$y$砍掉,如果$y$是$x$的$biu$,那就$x$的$biu$清零,否则照正常操作$cut$。$link$同理,但记得如果照正常套路$link$的话$x$的$biu$要清零,下面会说。
来看修改操作。由于要变信息所以把他$access+splay$后直接换信息再$up$最方便。然后来改爸爸,首先和原爸爸$cut$掉,然后和新爸爸$link$上。等会,这里原来有条$biu$边的,操作完之后可能$biu$边不$biu$了,也就是可能环上除了$biu$的一条边被$cut$了,那就$link$一下他(被修改点)所在的树的根节点以及根节点的$biu$,如果真的发生了这种情况,在$link$那里直接$biu$清零并将之连上。
然后询问。先找到真正的根节点(不是辅助splay树上的)$root$的$biu$,$access(biu)$,然后把那系数整理出来带进扩欧求解,有解的话就求出$root$的值,然后$access$查询点再$splay(root)$,$root$的右儿子上的系数就是用$root$的值求询问点的值的对应系数。
1 #include<string.h> 2 #include<stdlib.h> 3 #include<stdio.h> 4 #include<math.h> 5 //#include<assert.h> 6 #include<algorithm> 7 #include<iostream> 8 //#include<bitset> 9 using namespace std; 10 11 int n,m; 12 #define maxn 30011 13 const int mod=1e4+7; 14 int exgcd(int a,int b,int &x,int &y) 15 { 16 if (!b) {x=1; y=0; return a;} 17 else 18 { 19 int tmp=exgcd(b,a%b,y,x); 20 y-=a/b*x; return tmp; 21 } 22 } 23 int solve(int a,int b) 24 { 25 b=-b; 26 if (a==0) 27 { 28 if (b==0) return -2; 29 else return -1; 30 } 31 if (a<0) {a=-a; b=-b;} 32 if (b<0) b+=mod; 33 int x,y;exgcd(a,mod,x,y); 34 x=((1ll*b*x%mod)+mod)%mod; 35 return x; 36 } 37 38 struct LCT 39 { 40 struct Node 41 { 42 int fa,son[2]; 43 int biu; 44 int k,b,kk,bb; 45 }a[maxn]; 46 LCT() {a[0].k=a[0].kk=1;} 47 void makeatree(int id,int k,int b) 48 { 49 a[id].fa=a[id].son[0]=a[id].son[1]=a[id].biu=0; 50 a[id].k=a[id].kk=k; a[id].b=a[id].bb=b; 51 } 52 void up(int x) 53 { 54 if (!x) return; 55 int &p=a[x].son[0],&q=a[x].son[1]; 56 a[x].kk=a[p].kk*1ll*a[x].k%mod*a[q].kk%mod; 57 a[x].bb=a[q].bb+1ll*a[x].b*a[q].kk%mod+1ll*a[p].bb*a[q].kk%mod*a[x].k%mod; a[x].bb%=mod; 58 } 59 bool isroot(int x) 60 { 61 if (!a[x].fa) return 1; 62 return (a[a[x].fa].son[0]!=x && a[a[x].fa].son[1]!=x); 63 } 64 void rotate(int x) 65 { 66 const int y=a[x].fa,z=a[y].fa; 67 bool w=(x==a[y].son[0]); 68 a[x].fa=z; 69 if (!isroot(y)) a[z].son[y==a[z].son[1]]=x; 70 a[y].son[w^1]=a[x].son[w]; 71 if (a[x].son[w]) a[a[x].son[w]].fa=y; 72 a[x].son[w]=y; 73 a[y].fa=x; 74 up(y); up(z); 75 } 76 void splay(int x) 77 { 78 if (!x) return; 79 while (!isroot(x)) 80 { 81 const int y=a[x].fa,z=a[y].fa; 82 if (!isroot(y)) 83 { 84 if ((y==a[z].son[0])^(x==a[y].son[0])) rotate(x); 85 else rotate(y); 86 } 87 rotate(x); 88 } 89 up(x); 90 } 91 void access(int x) 92 { 93 int y=0,tmp=x; 94 while (x) {splay(x); a[x].son[1]=y; up(x); y=x; x=a[x].fa;} 95 splay(tmp); 96 } 97 int findroot(int x) 98 { 99 while (a[x].fa) x=a[x].fa; 100 return x; 101 } 102 void link(int x,int y) 103 { 104 if (!y) return; 105 if (findroot(x)==findroot(y)) a[x].biu=y; 106 else 107 { 108 a[x].biu=0; 109 access(x); 110 a[x].fa=y; 111 } 112 } 113 void cut(int x,int y) 114 { 115 if (y==a[x].biu) a[x].biu=0; 116 else 117 { 118 access(x); 119 if (a[x].son[0]) a[a[x].son[0]].fa=0; 120 a[x].son[0]=0; up(x); 121 } 122 } 123 void modify(int x,int y,int z,int k,int b) 124 { 125 access(x); 126 a[x].k=k; a[x].b=b; up(x); 127 int root=x; while (a[root].son[0]) root=a[root].son[0]; 128 cut(x,y); link(root,a[root].biu); link(x,z); 129 } 130 int query(int x) 131 { 132 int root=findroot(x); 133 while (a[root].son[0]) root=a[root].son[0]; splay(root); 134 int y=a[root].biu; access(y); 135 int tmp=solve(a[y].kk-1,a[y].bb); 136 if (tmp<0) return tmp; 137 tmp=(1ll*tmp*a[root].k+a[root].b)%mod; 138 if (x==root) return tmp; 139 access(x); 140 splay(root); 141 y=a[root].son[1]; 142 return (a[y].kk*1ll*tmp+a[y].bb)%mod; 143 } 144 }t; 145 146 int p[maxn]; 147 int main() 148 { 149 scanf("%d",&n); 150 for (int i=1,x,y;i<=n;i++) 151 { 152 scanf("%d%d%d",&x,&p[i],&y); 153 t.makeatree(i,x,y); 154 } 155 for (int i=1;i<=n;i++) t.link(i,p[i]); 156 scanf("%d",&m); 157 int x,y,z,w; char c; 158 while (m--) 159 { 160 while ((c=getchar())!='A' && c!='C'); 161 if (c=='A') 162 { 163 scanf("%d",&x); 164 printf("%d\n",t.query(x)); 165 } 166 else 167 { 168 scanf("%d%d%d%d",&x,&y,&z,&w); 169 t.modify(x,p[x],z,y,w); 170 p[x]=z; 171 } 172 } 173 return 0; 174 }