您的位置:首页 > 其它

【bzoj4150】[AMPPZ2014]The Staging 线段树

2015-10-22 16:47 417 查看
在舞台上有n个枪手,第i个枪手瞄准了第p[i]个枪手,将于第u[i]秒开枪。一个枪手如果成功开枪,
那么被瞄准的枪手会立刻死亡。
现在给出q次修改操作,请在一开始和每次修改操作后统计出最后存活的枪手个数。
p[i]互不相同,p[i] != i。
首先发现枪手形成若干环。于是可以用线段树维护,一个区间的开头那个人的状态对应结尾的状态,以及存活人数。
其他想法:u[i]折线图中只有下降的区间才有存活的人,不知可否用set。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
#define u t[x]
#define Lc t[x + x]
#define Rc t[x + x + 1]
using namespace std;
typedef long long LL;
const int N = 200005;
struct arr { int p[2], q[2], m; } t[N * 8]; // 0 -> alive 1 -> die
int n, m, c
, l1
, r1
, p
, lt, pre
, a
, pl, s1, tot, n1
, n2
, ql, qr, q, sum
, T, ans;
bool vis
, d
;
void Upd(int x) {
Rep(i, 0, 1) {
u.p[i] = Rc.p[ Lc.p[i] ];
u.q[i] = Lc.q[i] + Rc.q[ Lc.p[i] ];
} u.m = (a[Lc.m] < a[Rc.m]) ? Lc.m : Rc.m;
}
void Build(int x, int l, int r) {
if (l == r) {
u.p[0] = 1, u.p[1] = d[l], u.q[0] = 1, u.m = l;
return ;
}
int mid = l + r >> 1;
Build(x + x, l, mid), Build(x + x + 1, mid + 1, r);
Upd(x);
}
void Change(int x, int l, int r) {
if (l == r) {
u.p[1] = d[l], u.m = l; return ;
}
int mid = l + r >> 1;
if (q <= mid) Change (x + x, l, mid);
else Change (x + x + 1, mid + 1, r);
Upd(x);
}
void Find(int x, int l, int r) {
if (ql > r || qr < l) return ;
if (ql <= l && r <= qr) {
if (a[pl] > a[u.m]) pl = u.m; return ;
}
int mid = l + r >> 1;
Find(x + x, l, mid), Find(x + x + 1, mid + 1, r);
}
void Qry(int x, int l, int r) {
if (ql > r || qr < l) return ;
if (ql <= l && r <= qr) {
tot += u.q[s1]; s1 = u.p[s1]; return ;
}
int mid = l + r >> 1;
Qry(x + x, l, mid), Qry(x + x + 1, mid + 1, r);
}
void Prework() {
Rep(i, 1, n) if (!vis[i]) {
int j = i; l1[++ m] = lt + 1;
do {
vis[j] = 1;
a[++ lt] = c[j], d[lt + 1] = (c[ p[j] ] < c[j]); pre[ p[j] ] = j;
n1[j] = lt, n2[j] = m; j = p[j];
} while (j != i);
r1[m] = lt, d[ l1[m] ] = d[lt + 1];
}
Build(1, 1, n);
Rep(i, 1, m) {
pl = l1[i], tot = 0;
Rep(j, l1[i], r1[i]) if (a[pl] > a[j]) pl = j;
s1 = 0, ql = pl, qr = r1[i], Qry(1, 1, n);
ql = l1[i], qr = pl - 1, Qry(1, 1, n);
tot -= s1, sum[i] = tot, ans += sum[i];
}
printf("%d\n", ans);
}
int main()
{
scanf ("%d", &n);
Rep(i, 1, n) scanf ("%d", &p[i]);
Rep(i, 1, n) scanf ("%d", &c[i]);
Prework();
scanf ("%d", &T);
while (T --) {
int x, y, z;
scanf ("%d%d", &x, &y);
q = n1[x], a[q] = y, z = n2[x]; c[x] = y;
d[q] = c[x] < c[ pre[x] ], d[ n1[ p[x] ] ] = c[ p[x] ] < c[x];
Change(1, 1, n), q = n1[ p[x] ], Change(1, 1, n);
ql = l1[z], qr = r1[z], pl = n1[x], Find(1, 1, n);
tot = 0, s1 = 0;
ql = pl, qr = r1[z], Qry(1, 1, n);
ql = l1[z], qr = pl - 1, Qry(1, 1, n);
tot -= s1, ans += tot - sum[z]; sum[z] = tot;
printf("%d\n", ans);
}

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