题目描述
南极的企鹅王国大学中生活着 n n n 只企鹅,作为 21 21 21 世纪的优秀大学生,企鹅们积极响应“大众创业,万众创新”的号召,纷纷创业。但是创业需要资金,企鹅们最近手头比较紧,只能互相借钱。
企鹅的借钱行为是有规律可循的:每只企鹅只会借一次钱,并且只会从一只企鹅那里借钱。借钱关系中不存在环(即不存在类似“金企鹅欠银企鹅钱,银企鹅欠铜企鹅钱,铜企鹅欠金企鹅钱”这种情况)。
企鹅的还钱行为也是有规律可循的:每只企鹅一旦新获得了一笔钱,就会立刻用这笔钱尽可能偿还自己欠的债务,直到债务偿清或用光这笔钱。它只会使用新获得的这笔钱,至于以前它有没有钱、有多少钱,与还钱行为无关。
企鹅们经常会做美梦。在一只企鹅 A A A 的梦里,它梦见自己创业成功,一下子获得了 + ∞ +∞ +∞ 元钱,于是(按照上文的还钱规则)它赶快把钱用来还债,接着拿到钱的那只企鹅也赶快把钱用来还债……如此往复,直到所有获得钱的企鹅都完成了还债操作。梦醒之后,它开心地把梦的内容告诉了另外一只企鹅 B B B,企鹅 B B B 听了,也很开心,于是它问道:在你的梦里,我获得了多少钱呢?(指 B B B 去还债之前手里的钱,包括后来用于还债的钱和还债后 B B B 手里剩下的钱。)
梦毕竟是梦,对实际的欠债情况没有影响。
输入输出格式
输入格式
第一行两个整数 n n n 和 m m m,表示有 n n n 只企鹅, m m m 个操作。
接下来 m m m 行,有两种可能的格式:
0 a b c
:修改操作,企鹅
a
a
a 向企鹅
b
b
b 借了
c
c
c 元钱。1 a b
:查询操作,询问假如
a
a
a 有了
+
∞
+∞
+∞ 元钱,企鹅
b
b
b 会净收入多少钱。
本题强制在线,也就是说:对于每个操作输入的变量 a , b , c a, b, c a,b,c(如果没有 c c c,那就只有 a , b a, b a,b)都不是实际的 a , b , c a, b, c a,b,c,想获得实际的 a , b , c a, b, c a,b,c 应当经过以下操作:
a = ( a + l a s t a n s ) % n + 1 ; a = (a + lastans) \% n + 1; a=(a+lastans)%n+1;
b = ( b + l a s t a n s ) % n + 1 ; b = (b + lastans) \% n + 1; b=(b+lastans)%n+1;
c = ( c + l a s t a n s ) % n + 1 ; c = (c + lastans) \% n + 1; c=(c+lastans)%n+1;
其中, l a s t a n s lastans lastans 是上一次询问的答案。如果没有上一次询问, l a s t a n s lastans lastans 为 0 0 0。
输出格式
对每个询问操作,输出一行一个数表示答案。
输入输出样例
输入样例#1:
5 9
0 1 2 1
0 0 1 2
1 0 1
1 2 4
0 2 1 1
1 2 0
0 3 1 0
1 4 2
1 3 4
输出样例#1:
3
2
0
1
0
解题分析
一句话题意: 链上最小值带 l i n k link link操作。
直接大力 L C T LCT LCT就好了,但是拆边为点会 T T T掉一个点。
我们可以将边的权值下放到下端的点, 然后查询的时候查上方点的左儿子的信息就好了。
注意 s p l i t split split操作后需要重新 m a k e r o o t makeroot makeroot, 因为这是一棵有根树。
据说还可以用倍增+启发式合并做, 不过我太蒟了只敢写 L C T LCT LCT的QAQ
代码如下:
#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#define R register
#define IN inline
#define W while
#define MX 100050
inline char nc()
{
static const int buflen=1e6;
static char buf[buflen],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,buflen,stdin),p1==p2)?EOF:*p1++;
}
void out(int x)
{
if(x>9)out(x/10);
putchar(x%10+'0');
}
#define gc nc()
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int dot, cnt, lastans, q, top;
int sta[MX], bel[MX];
struct Node {int son[2], mn, val, fat; bool rev;} tree[MX];
int find(R int now) {return bel[now] == now ? now : bel[now] = find(bel[now]);}
namespace LCT
{
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define dad tree[now].fat
IN bool get(R int now) {return tree[dad].son[1] == now;}
IN bool nroot(R int now) {return tree[dad].son[1] == now || tree[dad].son[0] == now;}
IN void pushrev(R int now) {std::swap(ls, rs), tree[now].rev ^= 1;}
IN void pushdown(R int now) {if(tree[now].rev) tree[now].rev = false, pushrev(ls), pushrev(rs);}
IN void pushup(R int now)
{
tree[now].mn = tree[now].val;
if(ls) tree[now].mn = std::min(tree[now].mn, tree[ls].mn);
if(rs) tree[now].mn = std::min(tree[now].mn, tree[rs].mn);
}
IN void rotate(R int now)
{
R int fa = dad, grand = tree[fa].fat;
R bool dir = get(now);
tree[fa].son[dir] = tree[now].son[dir ^ 1];
tree[tree[now].son[dir ^ 1]].fat = fa;
tree[now].fat = grand;
if(nroot(fa)) tree[grand].son[get(fa)] = now;
tree[now].son[dir ^ 1] = fa;
tree[fa].fat = now;
pushup(fa);
}
IN void splay(R int now)
{
R int tmp = now, fa;
sta[top = 1] = now;
W (nroot(now)) sta[++top] = now = dad;
W (top) pushdown(sta[top--]);
now = tmp;
W (nroot(now))
{
fa = dad;
if(nroot(fa)) rotate(get(fa) == get(now) ? fa : now);
rotate(now);
}
pushup(now);
}
IN int access(R int now)
{
R int x = 0;
for (; now; x = now, now = dad)
splay(now), rs = x, pushup(now);
return x;
}
IN int lca(R int x, R int y) {access(x); return access(y);}
IN void link(R int x, R int y) {splay(x); tree[x].fat = y;}
IN void makeroot(R int x) {access(x), splay(x), pushrev(x);}
IN void split(R int x, R int y) {makeroot(x), access(y), splay(y);}
#undef ls
#undef rs
#undef dad
}
int main(void)
{
int opt, a, b, c;
in(dot), in(q);
for (R int i = 1; i <= dot; ++i) bel[i] = i, tree[i].val = tree[i].mn = 100000000;
W (q--)
{
in(opt), in(a), in(b);
a = (a + lastans) % dot + 1, b = (b + lastans) % dot + 1;
if(!opt) in(c), c = (c + lastans) % dot + 1;
if(!opt)
{
bel[find(a)] = find(b); tree[a].val = tree[a].mn = c;
LCT::link(a, b);
}
else
{
if(find(a) != find(b)) {out(lastans = 0); puts(""); continue;}
if(LCT::lca(a, b) == b)
{
int rt = bel[b];
LCT::split(a, b);
out(lastans = tree[tree[b].son[0]].mn); puts("");
LCT::makeroot(rt);
}
else out(lastans = 0), puts("");
}
}
}