发现当存在一个环,就可以求出环所在联通块上所有点的答案.
既然题目都告诉我是lct了,就想着搞一搞,
用splay维护每个点对根的方程,即splay维护这颗splay中深度最深的节点对于深度最浅节点的方程
然后脑子木的以为有很多非树边,在哪里各种乱搞,,各种暴力枚举想水一水...
我大概是个智障.
正解:
边是有向的,i->p[i]
有脑子的人都会知道这是一颗基环内向树
基环树有个套路就是不需要换根操作,把环上一条边拆了,其中一个点看做根,另一个点看做根的special_father
那么就很好做了,splay像上面那样维护.
link的时候如果没联通就直接link,否则只是把i的special_father设为p[i]
cut的时候如果是cut掉special_father.直接把special_father设为0
否则先cut成两个联通块,然后找到开始的根,若根的special_father重新联通这两个联通块就把这条边变成正常的树边,link起来,special_father设为0
查询的时候,access根的special_father即可算出根的答案,再access要查询的点即可
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<cstdio>
7 #include<cmath>
8 #include<queue>
9 #include<set>
10 #include<map>
11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
13 const int N=30000+7,P=10007;
14 typedef long long LL;
15 typedef double db;
16 using namespace std;
17 int n,Q,inv[P+7];
18 char o[10];
19
20 template<typename T>void read(T &x) {
21 char ch=getchar(); x=0; T f=1;
22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
23 if(ch=='-') f=-1,ch=getchar();
24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
25 }
26
27 int ch[N][2],p[N],sp[N],pp[N];
28 #define lc ch[x][0]
29 #define rc ch[x][1]
30 struct data {
31 int k,b;
32 data(){ k=1; b=0; }
33 data(int k,int b):k(k),b(b){}
34 friend data operator *(const data&A,const data&B) {
35 return data(A.k*B.k%P,(A.b*B.k%P+B.b)%P);
36 }
37 }sum[N],dt[N];
38
39 int isroot(int x) { return (ch[p[x]][0]!=x&&ch[p[x]][1]!=x); }
40
41 void update(int x) { sum[x]=sum[lc]*dt[x]*sum[rc]; }
42
43 void rotate(int x) {
44 int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
45 if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
46 ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
47 ch[x][r]=y; p[y]=x;
48 update(y); update(x);
49 }
50
51 void splay(int x) {
52 for(;!isroot(x);rotate(x)) {
53 int y=p[x],z=p[y];
54 if(!isroot(y))
55 ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
56 }
57 }
58
59 void access(int x) {
60 for(int t=0;x;x=p[t=x]) {
61 splay(x);
62 rc=t;
63 update(x);
64 }
65 }
66
67 int find_root(int x) {
68 access(x);
69 splay(x);
70 while(lc) x=lc;
71 return x;
72 }
73
74 void lik(int x,int y) {
75 if(find_root(x)==find_root(y)) {
76 sp[x]=y; return;
77 }
78 splay(x);
79 p[x]=y;
80 }
81
82 void cut(int x,int y) {
83 if(sp[x]==y) {
84 sp[x]=0; return;
85 }
86 int z=find_root(x);
87 lc=p[lc]=0;
88 update(x);
89 if(sp[z]&&find_root(sp[z])!=find_root(z)) {
90 access(z);
91 splay(z);
92 p[z]=sp[z];
93 sp[z]=0;
94 }
95 }
96
97 void exgcd(int a,int b,int &x,int &y) {
98 if(!b) { x=1; y=0; return; }
99 exgcd(b,a%b,y,x); y-=a/b*x;
100 }
101
102 void qry(int x) {
103 int y=find_root(x);
104 if(!sp[y]) puts("-2");
105 else {
106 access(sp[y]);
107 splay(sp[y]);
108 data tp=sum[sp[y]];
109 if(tp.k&&(!tp.b)) { puts("-1"); return; }
110 int a=(1-tp.k+P)%P;
111 int rs=!tp.k?tp.b:inv[a]*tp.b%P;
112 access(x);
113 splay(x);
114 rs=(sum[x].k*rs%P+sum[x].b)%P;
115 printf("%d
",rs);
116 }
117 }
118
119 //#define DEBUG
120 int main() {
121 #ifdef DEBUG
122 freopen("1.in","r",stdin);
123 //freopen("1.out","w",stdout);
124 #endif
125 read(n);
126 inv[0]=inv[1]=1;
127 For(i,2,P) inv[i]=(P-P/i*inv[P%i]%P)%P;
128 For(i,1,n) {
129 read(dt[i].k); read(pp[i]); read(dt[i].b);
130 lik(i,pp[i]);
131 }
132 read(Q);
133 while(Q--) {
134 scanf("%s",o);
135 if(o[0]=='A') {
136 int xx;
137 read(xx);
138 qry(xx);
139 }
140 else {
141 int xx,kk,ppp,bb;
142 read(xx); read(kk); read(ppp); read(bb);
143 cut(xx,pp[xx]);
144 splay(xx);
145 dt[xx].k=kk; dt[xx].b=bb;
146 update(xx);
147 pp[xx]=ppp;
148 lik(xx,pp[xx]);
149 }
150 }
151 return 0;
152 }
我真的好菜呀,,什么"经典模型","套路","众所周知的" 都不知道,什么"大水题","送分题","普及-的题"都做不来...