您的位置:首页 > 其它

【Hdu】1540 Tunnel Warfare(线段树|区间合并)

2015-03-06 16:43 232 查看
题目大意:有N个村子排成一条直线,每个村子都连接了它的左右两个村子(除了最左边和最右边的外),有3种操作,(1)"D x",表示将第x个村子摧毁。(2)"Qx",表示查询与第x个村子直接和间接相连的村子有多少个。(3)"R",表示将上一次摧毁的村子复原。

这边有一个需要注意的点是村子可以多次被摧毁,但只需要一次便可恢复。

思路:

这边我只用两个数组lsum,和rsum

其中作用分别是表示左边界向右连续的最大长度,右边界向左连续的最大长度

然后先询问的函数query中,所采用的是不断缩放区间,直到最后成为一个点,并且缩放后区间的lsum和rsum的意义也发生改变

lsum表示的是左边界向左连续的最大长度,rum表示右边界向右连续的最大长度,这样最后对于询问的点q,lsum表示的就是不包括该点向左连续的最大长度,rsum表示的就是不包括该点向右连续的最大长度。

有了这个思想基础之后,剩下的便是转化了,搞了好久。详细看代码吧。

#define  _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
using namespace std;
#define MAX 50005
#define ls rt<<1
#define rs ls|1
#define m (l+r)>>1

int lsum[MAX << 2];
int rsum[MAX << 2];
int bb[MAX];
int ans;

void uprt(int len, int rt)
{
lsum[rt] = lsum[ls];
rsum[rt] = rsum[rs];
if (lsum[rt] == len - (len >> 1))
lsum[rt] += lsum[rs];
if (rsum[rt] == (len >> 1))
rsum[rt] += rsum[ls];
}

void updata(int q, int c, int l, int r, int rt)
{
if (l == r)
{
lsum[rt] = rsum[rt] = c;
bb[l] = c;
return;
}
int mid = m;
if (q <= mid)
updata(q, c, l, mid, ls);
else
updata(q, c, mid + 1, r, rs);
uprt(r - l + 1, rt);
}

void query(int q, int l, int r, int rt)
{
if (l == r)
{
ans = (lsum[rt] + rsum[rt])*bb[l] + bb[l];
return;
}
int mid = m;
int len = r - l + 1;
int a, b;
if (q <= mid)
{
a = rsum[ls];
b = lsum[ls];
if (rsum[ls] != 0)
rsum[ls] = lsum[rs];
if (lsum[rs] == (len >> 1))
rsum[ls] += rsum[rt];
lsum[ls] = lsum[rt];
query(q, l, mid, ls);
rsum[ls] = a;
lsum[ls] = b;
}
else
{
a = rsum[rs];
b = lsum[rs];
if (lsum[rs] != 0)
lsum[rs] = rsum[ls];
if (rsum[ls] == len - (len >> 1))
lsum[rs] += lsum[rt];
rsum[rs] = rsum[rt];
query(q, mid + 1, r, rs);
rsum[rs] = a;
lsum[rs] = b;
}
}

void reset(int l, int r, int rt)
{
if (l == r)
return;
int mid = m;
reset(l, mid, ls);
reset(mid + 1, r, rs);
uprt(r - l + 1, rt);
}

void build(int l, int r, int rt)
{
if (l == r)
{
rsum[rt] = lsum[rt] = 1;
bb[l] = 1;
return;
}
int mid = m;
build(l, mid, ls);
build(mid + 1, r, rs);
uprt(r - l + 1, rt);
}

int main()
{
int n, k;
char str[2];
int a;
while (~scanf("%d%d", &n, &k))
{
stack<int>pre;
build(1, n, 1);
for (int i = 0; i < k; i++)
{
scanf("%s", str);
if (str[0] == 'D')
{
scanf("%d", &a);
pre.push(a);
updata(a, 0, 1, n, 1);
continue;
}
if (str[0] == 'Q')
{
scanf("%d", &a);
lsum[1] = 0;
rsum[1] = 0;
query(a, 1, n, 1);
printf("%d\n", ans);
continue;
}
if (!pre.empty())
{
while (pre.empty() && bb[pre.top()])
pre.pop();
updata(pre.top(), 1, 1, n, 1);
pre.pop();
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: