PKU 2892 [HDU 1540]
题型:线段树
描述:n个村子排成一条线,两两相邻,1.摧毁村子c,2.修复上一次摧毁的村子,3.问与村子c直接或间接相通的村子数
思路:对节点的操作,增加lx,rx域,表示区间内最左边被摧毁的村子,和最右边被摧毁的村子,s表示区间内摧毁的村子总数。
重点在count(),统计相连村子数操作。根据父结点的两个孩子结点的 s 值,讨论各种可能情况。
if (t[k0].s == 0) {
if (t[k0+1].s == 0) cnt = t[k].r-t[k].l+1;
else if (t[k0+1].lp > a) cnt = t[k0].r-t[k0].l+1+t[k0+1].lp-t[k0+1].l;
else count(a, k0+1);
}else {
if (t[k0+1].s == 0 && t[k0].rp < a)
cnt = t[k0+1].r-t[k0+1].l+1+t[k0].r-t[k0].rp;
else if (a>t[k0].rp && a<t[k0+1].lp)
cnt = t[k0].r-t[k0].rp + t[k0+1].lp-t[k0+1].l;
else {
if (a <= md) count(a, k0);
else count(a, k0+1);
}
}
完整代码
//234MS 2804K
#include <stdio.h>
#include <string.h>
#define NL 65536
struct Seg {
int l, r;
int lp, rp, s;
}t[NL*2];
bool dt[50001];//1 没被摧毁 0 被摧毁
int stk[50001];
int cnt;
void build(int l, int r, int k)
{
t[k].l = l;
t[k].r = r;
t[k].s = 0;
t[k].lp = t[k].rp = 0;
if (l == r) dt[l] = 1;
int md = (l+r)>>1, k0 = k<<1;
if (l < r) {
build(l, md, k0);
build(md+1, r, k0+1);
}
}
//flg = 0 摧毁,flg = 1 恢复
void mody(int a, int k, bool flg)
{
if (t[k].l == t[k].r) {
if (flg) t[k].s = 0, dt[a] = 1;
else {
t[k].s = 1;
t[k].lp = t[k].rp = a;
dt[a] = 0;
}
return;
}
int md = (t[k].l+t[k].r)>>1, k0 = k<<1;
if (a <= md)
mody(a, k0, flg);
else if (a > md)
mody(a, k0+1, flg);
t[k].s = t[k0].s + t[k0+1].s;
if (t[k].s) {
t[k].lp = t[k0].lp;
t[k].rp = t[k0+1].rp;
if (t[k0].s == 0) t[k].lp = t[k0+1].lp;
if (t[k0+1].s == 0) t[k].rp = t[k0].rp;
}
}
void count(int a, int k)
{
if (t[k].l == t[k].r) {
cnt = 1;
return;
}
int md = (t[k].l+t[k].r)>>1, k0 = k<<1;
if (t[k0].s == 0) {
if (t[k0+1].s == 0) cnt = t[k].r-t[k].l+1;
else if (t[k0+1].lp > a) cnt = t[k0].r-t[k0].l+1+t[k0+1].lp-t[k0+1].l;
else count(a, k0+1);
}else {
if (t[k0+1].s == 0 && t[k0].rp < a)
cnt = t[k0+1].r-t[k0+1].l+1+t[k0].r-t[k0].rp;
else if (a>t[k0].rp && a<t[k0+1].lp)
cnt = t[k0].r-t[k0].rp + t[k0+1].lp-t[k0+1].l;
else {
if (a <= md) count(a, k0);
else count(a, k0+1);
}
}
}
int main()
{
int n, m, a, top;
char c[3];
// freopen("in.txt", "r", stdin);
while (scanf("%d%d", &n, &m) != EOF) {
build(1, n, 1);
top = 0;
while (m--) {
scanf("%s", c);
if (c[0] == 'D') {
scanf("%d", &a);
stk[top++] = a;
mody(a, 1, 0);
}else if (c[0] == 'Q') {
scanf("%d", &a);
cnt = 0;
if (dt[a])
count(a, 1);
printf("%d\n", cnt);
}else {
a = stk[--top];
mody(a, 1, 1);
}
}
}
return 0;
}