[BZOJ]2759 一个动态树好题 LCT + 数学 + 好题[真]
来源:互联网 发布:淘宝猜你喜欢位置在哪 编辑:程序博客网 时间:2024/06/06 16:42
2759: 一个动态树好题
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 820 Solved: 278
[Submit][Status][Discuss]
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%
Sample Input
5
2 2 1
2 3 2
2 4 3
2 5 4
2 3 5
5
A 1
A 2
C 5 3 1 1
A 4
A 5
Sample Output
4276
7141
4256
2126
HINT
Source
By 范浩强
[Submit][Status][Discuss]
HOME Back
题解
这道题是真的动态树好题… 突然想起某道绝世好题[假] —- 其实是绝世水题.
需要对LCT维护方式很清晰才能来捉此题… 一开始一直T后来才发现vis开的bool数组… 样例太水.
首先对于每个同余方程的x将对应的p作为fa. 这样由于有n个点, 每个点都有fa, 所以一定是基环外向树森林… 基环外向树我的浅显理解就是一棵树上有一个环. 一个点x记录fa之后, 方程就变成了:
x = k * fa + b (mod m)
我们考虑怎么求解同余方程. 显然当一个联通块里的环里的一个的方程解出来, 整个联通块都解出来了. 由于有修改操作这样的动态维护, 所以想到用数据结构. 由于是基环外向树, 所以又想到拆一条边变成树, 用LCT来维护树. 砍了一条边怎么办 ? 定义每个基环外向树有个根, 根与根的fa不连边, 记一个sp[root]表示根的特殊fa. 这样将sp[root] access之后, 就能得到n个同余方程, 并且每个方程的另一个未知数(p)存在于这n个同余方程之中, 这样必定有解, 就能够解出一个解, 如果就想解出sp[root]是多少的话, 那么说明LCT需要维护最深的那个点的解.
那么考虑怎么维护: 一个x和他的fa的方程分别为
x = f * k1 + b1
f = ff * k2 + b2
合并成一个fa之后即为 x = k1 * (ff * k2 + b2) + b1, 这是一个关于解出x的方程. 记splay里每个点子树合并的最终方程为sum[x].这样splay里就可以update了, 但是必须要求是x和他的f才能合并. 这里有一个神奇的技巧, 那就是从下往上update的时候, 先合并sum[ls]和sum[x] (先后顺序有影响),再合并sum[x] 和 sum[rs[x]], 这样的合并顺序就能保证每次合并合法, 并且保存的是解出最深的那个点的解.
这样access sp[root]后, n个互相关联的同余方程合并最后会长成这个样子.
x(sp[root]) = k * x + b;求个逆元即可求出.
修改分类讨论:;
如果要改的点是一个root,那么直接修改sp就行了,否则我们要看要修改点是否在环
上,若在环上需要删边后先将root指向sp的边加进去,然后看是否会出现新环,有就讲新
父亲作为sp,否则直接连虚边。
具体见代码.
Tips:
1. 任何对一个点的访问或操作, 都要先access并splay.
2.由于根保存了信息, 所以根是固定的, 不能makeroot.
#include<bits/stdc++.h>#define mod 10007#define Boc register char#define Acce register intusing namespace std;const int maxn = 4e4 + 5;char ss[4];int n, q, idx;int fa[maxn], c[maxn][2], inv[maxn], sp[maxn], vis[maxn];inline const int read(){ Acce x = 0, f = 1; Boc ch = getchar(); while (ch < '0' || ch > '9') {if(ch == '-')f = -1;ch = getchar();} while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return f * x; }struct node{ int k, b; node(){} node(int k, int b) : k(k), b(b) {} friend node operator + (const node &x, const node &y) { return node(x.k * y.k % mod, (y.k * x.b % mod + y.b) % mod); }}a[maxn], sum[maxn];void dfs(int x){ vis[x] = idx; if (vis[fa[x]] == idx) { sp[x] = fa[x]; fa[x] = 0; } else if (! vis[fa[x]]) dfs(fa[x]);}inline void init(){ inv[1] = 1; for (int i = 2; i < mod; ++ i) inv[i] = (mod - mod / i) * inv[mod % i] % mod;}inline bool isroot(int x){ return (c[fa[x]][0] != x && c[fa[x]][1] != x) || ! fa[x]; }inline void update(int x){ sum[x] = a[x]; if (c[x][0]) sum[x] = sum[c[x][0]] + a[x]; if (c[x][1]) sum[x] = sum[x] + sum[c[x][1]];}inline void rotate(int x){ int y = fa[x], z = fa[y]; int l = (c[y][0] != x), r = l ^ 1; if (! isroot(y)) c[z][c[z][0] != y] = x; fa[x] = z, fa[y] = x, fa[c[x][r]] = y; c[y][l] = c[x][r], c[x][r] = y; update(y), update(x);}inline void splay(int x){ for (int f; ! isroot(x); rotate(x)) if (! isroot((f = fa[x]))) rotate((c[fa[f]][0] == f ^ c[f][0] == x) ? x : f); }inline void access(int x){ for (int t = 0; x; x = fa[x]) splay(x), c[x][1] = t, update(x), t = x;}inline void cut(int x){ access(x), splay(x); c[x][0] = fa[c[x][0]] = 0; update(x);}inline int findroot(int x) { access(x), splay(x); while (c[x][0]) x = c[x][0]; splay(x); return x;}inline bool incircle(int x, int y){ access(sp[y]), splay(sp[y]); splay(x); return x == sp[y] || ! isroot(sp[y]);}int main(){ init(); n = read(); for (Acce i = 1; i <= n; ++ i) a[i].k = read(), fa[i] = read(), a[i].b = read(); for (Acce i = 1; i <= n; ++ i) if(!vis[i]) ++ idx, dfs(i); q = read(); int x, k, p, b, t; for (Acce i = 1; i <= q; ++ i) { scanf("%s", ss); if (ss[0] == 'A') { scanf("%d", &x); access(x), splay(x); node t1 = sum[x]; x = findroot(x); access(sp[x]), splay(sp[x]); node t2 = sum[sp[x]]; if(t2.k == 1) (t2.b) ? puts("-1") : puts("-2"); else { int ni = inv[(1 - t2.k + mod) % mod] * t2.b % mod; printf("%d\n", (t1.k * ni % mod + t1.b) % mod); } } else { x = read(), k = read(), p = read(), b = read(); access(x), splay(x); a[x] = node(k, b), update(x); t = findroot(x); if(t == x) { if (findroot(p) == t) sp[t] = p; else sp[t] = 0, fa[t] = p; //link } else { if (incircle(x, t)) { cut(x); access(t), splay(t); fa[t] = sp[t], sp[t] = 0; if (findroot(p) == x) sp[x] = p; else fa[x] = p; } else { cut(x); if (findroot(p) == x) sp[x] = p; else fa[x] = p; } } } }}
- [BZOJ]2759 一个动态树好题 LCT + 数学 + 好题[真]
- bzoj 2759 一个动态树好题 LCT 数学
- [LCT 线性模方程] BZOJ 2759 一个动态树好题 & 4266 小强的动态方程
- BZOJ 5020 [LCT][数学]
- BZOJ 2759 一个动态树好题(Link-Cut Tree+数学)
- [LCT] BZOJ2759.一个动态树好题
- bzoj2759:一个动态树好题 (LCT+Exgcd)
- Bzoj-2759: 一个动态树好题
- [动态树 LCT] BZOJ 2157 旅游
- bzoj 3282 Tree 动态树LCT
- BZOJ 2716 LCT模板题
- BZOJ 2759 一道动态树的好题
- BZOJ 4300 绝世好题 动态规划
- BZOJ 4300: 绝世好题 动态规划
- bzoj 2002 Bounce 弹飞绵羊(LCT动态树)
- BZOJ 2049 Cave 洞穴勘测(LCT动态树)
- 【BZOJ】2631 tree LCT入门题
- bzoj 3282: Tree LCT第三题
- 黑五你剁了哪些靠谱的硬干货?
- 姿态检查整理--07-RMPE: Regional Multi-Person Pose Estimation
- 正则匹配1开头的11位数字
- 好的中式装修设计师能为我们做些什么呢
- 两台主机可以无需密码而直接互相登录的SSH配置方法
- [BZOJ]2759 一个动态树好题 LCT + 数学 + 好题[真]
- 7-39 字符串转换成十进制整数(15 分)
- HTML5离线存储原理
- 本地连接到solrcloud集群环境进行源码测试
- 大型网站架构 图片服务器分离
- 求1+2+3+...+n
- vga的各种概念
- PySpark处理数据并图表分析
- jsp往controller传值