题型:线段树
描述: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 ;
}