您的位置:首页 > 其它

BZOJ2002 [HNOI2010]Bounce 弹飞绵羊

2018-02-04 19:41 267 查看

Address

洛谷P3203 BZOJ2002

Solution

LCTLCT 模板题……

因为原图无环,把位置看做 nn 个点,用 LCTLCT 维护各点 szesze (子树大小)。

新增一个表示被弹飞的点 n+1n+1,则对于位置 ii :

若 i+ki≤ni+ki≤n,连边 (i,i+ki)(i,i+ki)

若 i+ki>ni+ki>n,连边 (i,n+1)(i,n+1)

对于初始时的 kiki 先连接上边

对于修改操作:断开原来的边再连接上新的边

对于询问操作:取出 LCTLCT 中 ii ~ n+1n+1 的实路径,输出顶部节点szesze

时间复杂度 均摊O(nlogn)O(nlog⁡n)

Code

#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>

using namespace std;

namespace inout
{
const int S = 1 << 20;
char frd[S], *ihed = frd + S;
const char *ital = ihed;

inline char inChar()
{
if (ihed == ital)
fread(frd, 1, S, stdin), ihed = frd;
return *ihed++;
}

inline int get()
{
char ch; int res = 0; bool flag = false;
while (!isdigit(ch = inChar()) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (isdigit(ch = inChar()))
res = res * 10 + ch - 48;
return flag ? -res : res;
}

char fwt[S], *ohed = fwt;
const char *otal = fwt + S;

inline char outChar(char ch)
{
if (ohed == otal)
fwrite(fwt, 1, S, stdout), ohed = fwt;
return *ohed++ = ch;
}

inline void put(int x)
{
if (x > 9) put(x / 10);
outChar(x % 10 + 48);
}
};
using namespace inout;

const int N = 2e5 + 5;
int n, m, k
;

inline int Min(int x, int y) {return x < y ? x : y;}

namespace LCT
{
int lc
, rc
, fa
, sze
, rev
;
int qr, que
;

inline bool Which(int x)
{
return lc[fa[x]] == x;
}

inline bool isRoot(int x)
{
return !fa[x] || lc[fa[x]] != x && rc[fa[x]] != x;
}

inline bool Uptdate(int x)
{
sze[x] = sze[lc[x]] + sze[rc[x]] + 1;
}

inline void pushDown(int x)
{
if (rev[x])
{
swap(lc[x], rc[x]);
if (lc[x]) rev[lc[x]] ^= 1;
if (rc[x]) rev[rc[x]] ^= 1;
rev[x] = 0;
}
}

inline void Rotate(int x)
{
int y = fa[x], z = fa[y],
b = lc[y] == x ? rc[x] : lc[x];
if (z && !isRoot(y))
(lc[z] == y ? lc[z] : rc[z]) = x;
fa[x] = z; fa[y] = x;
if (b) fa[b] = y;
if (lc[y] == x) rc[x] = y, lc[y] = b;
else lc[x] = y, rc[y] = b;
Uptdate(y);
}

inline void Splay(int x)
{
que[qr = 1] = x;
for (int y = x; !isRoot(y); y = fa[y]) que[++qr] = fa[y];
for (int i = qr; i; --i) pushDown(que[i]);

while (!isRoot(x))
{
if (!isRoot(fa[x]))
Which(fa[x]) == Which(x) ? Rotate(fa[x]) : Rotate(x);
Rotate(x);
}
Uptdate(x);
}

inline void Access(int x)
{
for (int y = 0; x; y = x, x = fa[x])
{
Splay(x); rc[x] = y;
if (y) fa[y] = x; Uptdate(x);
}
}

inline int findRoot(int x)
{
Access(x); Splay(x);
while (pushDown(x), lc[x]) x = lc[x];
Splay(x); return x;
}

inline void makeRoot(int x)
{
Access(x); Splay(x); rev[x] ^= 1;
}

inline void Link(int x, int y)
{
makeRoot(x); fa[x] = y;
}

inline void Cut(int x, int y)
{
makeRoot(x); Access(y); Splay(y);
lc[y] = fa[x] = 0; Uptdate(y);
}

inline int Select(int x, int y)
{
makeRoot(x); Access(y); Splay(y);
//把x置为根后,标记未下传,影响询问结果,因此Splay(y)
return sze[y] - 1;
}
};
using namespace LCT;

int main()
{
//  freopen("bounce.in", "r", stdin);
//  freopen("bounce.out", "w", stdout);

n = get() + 1;
for (int i = 1; i <= n; ++i) sze[i] = 1;
for (int i = 1; i < n; ++i)
k[i] = get(), Link(i, Min(i + k[i], n));

m = get(); int x, y;
while (m--)
{
x = get(); y = get() + 1;
if (x & 1)
put(Select(y, n)), outChar('\n');
else
{
Cut(y, Min(y + k[y], n));
k[y] = get();
Link(y, Min(y + k[y], n));
}
}
fwrite(fwt, 1, ohed - fwt, stdout);

//  fclose(stdin); fclose(stdout);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  LCT