HDOJ http://acm.hdu.edu.cn/showproblem.php?pid=1540 多cases
建立线段树,区间划分为[l, mid), [mid, r), 并记录区间从左右端点开始最大连续长度,初始时,即为整个区间长度,维护这样的结构可以查询与每个村庄相连的最多村庄。
线段树的每个区间维护:
从左端点开始的连续最大值 lval
从右端点开始的连续最大值 rval
区间的状态;0: 区间代表的所有村庄都毁掉
1: 所有村庄都完好
-1:有些毁坏,有些没有
村庄1,2,3,4,5,6,7可以用区间[1, 8)代表
毁坏村庄x的时候,可以看作对叶子区间[x, x+1)修改,修改维护的变量并向上一直更新父亲节点维护的变量
修复村庄同理
查询的时候,需要定位村庄所在区间,若区间内村庄都被毁或者都完好,则直接可以得到结果(0或者区间长)
处于混合状态,有时需要将左右孩子结果合并,否则继续递归查询。
合并的两种情况:
1: mid - l <= 左孩子从右端点起的最大连续长度
则结果为: 左孩子从右端点起的最大连续长度+右孩子从左端点起的最大连续长度
2: l-mid +1 <= 右孩子从左端点起的最大连续长度
则结果为: 左孩子从右端点起的最大连续长度+右孩子从左端点起的最大连续长度
l表示村庄,mid为线段树区间中点
注:代码里记录区间最大值的max其实没用--|||
/*===============================================================
* Copyright (C) 2012 All rights reserved.
*
* file: 2892_Tunnel_Warfare.cpp
* author: ivapple
* date: 2012-09-07
* description:
*
* update log:
*
================================================================*/
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <stack>
#include <string>
#include <cstring>
#define out(x) (cout<<#x<<": "<<x<<endl)
#define FOR(i,s,t) for(i=s; i<t; i++)
using namespace std;
template<class T>void show(T a, int n){int i; for(i=0;i<n;i++)cout<<a[i]<<" ";cout<<endl;}
template<class T>void show(T a, int r, int l){int i; for(i=0;i<r;i++)show(a[i],l);cout<<endl;}
const int kMaxVillage = 50001;
struct SegTree
{
int s, e; //[s,e)
int lc, rc; //left child, right child
int flag; //0 destroy, 1 not, -1 combine
int lval, rval, max;
}tree[4*kMaxVillage];
int id = -1;
void BuildTree(int l, int r)
{
int mid;
int root = ++id;
tree[root].s = l;
tree[root].e = r;
//cout << root << " " << l << " " << r << " " << endl;
//cout << tree[root].s << " " << tree[root].e << endl;
tree[root].flag = 1; //not destroy
tree[root].lval = tree[root].rval = tree[root].max = r-l; //length of region
if (l<r-1)
{
mid = (l+r)/2;
tree[root].lc = id+1;
BuildTree(l, mid);
tree[root].rc = id+1;
BuildTree(mid, r);
}
}
int Max(int a, int b, int c)
{
int max;
max = a>b?a:b;
max = max>c?max:c;
}
void Update(int root)
{
// update flag
int lc = tree[root].lc;
int rc = tree[root].rc;
if (tree[lc].flag == 1 && tree[rc].flag == 1) // all ok
tree[root].flag = 1;
else
if (tree[lc].flag == 0 && tree[rc].flag == 0) // all destroy
tree[root].flag = 0;
else
tree[root].flag = -1; //combine
// update value
tree[root].lval = tree[lc].lval + (tree[lc].flag == 1? tree[rc].lval:0);
tree[root].rval = tree[rc].rval + (tree[rc].flag == 1? tree[lc].rval:0);
//tree[root].max = Max(tree[lc].rval+tree[rc].lval, tree[root].lval, tree[root].rval);
}
//l is viilage number
//opt 1 repair
//opt 0 destory
void ModifyTree(int root, int l, int r, int opt)
{
//cout << l << " " << r << " " << root <<endl;
//out(tree[root].s);
//out(tree[root].e);
//leaf
if (l==tree[root].s && tree[root].e==r)
{
tree[root].flag = opt; //0 destroy 1 ok -1 combine
tree[root].lval = opt;
tree[root].rval = opt;
tree[root].max = opt;
return;
}
int mid = (tree[root].s+tree[root].e)/2;
if (l < mid)
ModifyTree(tree[root].lc, l, r, opt);
if (r > mid)
ModifyTree(tree[root].rc, l, r, opt);
Update(root);
}
int Query(int root, int l, int r)
{
int lc = tree[root].lc;
int rc = tree[root].rc;
//cout << root << " " << l << " " << r << endl;
if (tree[root].flag ==1) //all ok
return tree[root].e-tree[root].s;
if (tree[root].flag == 0) //all destory
return 0;
//if (tree[root].e-1 == tree[root].s)
// return 0;
int mid = (tree[root].s+tree[root].e)/2;
if (l < mid)
{
if (mid-l <= tree[lc].rval)
return tree[lc].rval + tree[rc].lval;
return Query(lc, l, r);
}
if (r > mid)
{
//cout << l <<" " << mid << " " <<rc << " " <<tree[rc].lval << endl;
if (l-mid+1 <= tree[rc].lval)
return tree[rc].lval + tree[lc].rval;
return Query(rc, l, r);
}
}
int main()
{
int n, m;
char cmd, buf;
int village;
int ans;
stack<int> st;
#ifndef ONLINE_JUDGE
freopen("test.txt", "r", stdin);
#endif
while (scanf("%d%d", &n, &m)!=EOF)
{
id = -1;
memset(tree,0,4*kMaxVillage);
BuildTree(1, n+1);
while (m--)
{
scanf("%c", &buf);
scanf("%c", &cmd);
// out(buf);
// out(cmd);
if (cmd == 'D')
{
scanf("%d", &village);
//out(village);
st.push(village);
ModifyTree(0, village, village+1, 0);
}
if (cmd == 'Q')
{
scanf("%d", &village);
//out(village);
ans = Query(0, village, village+1);
printf("%d\n", ans);
}
if (cmd == 'R')
{
village = st.top();
st.pop();
ModifyTree(0, village, village+1, 1);
}
}
}
return 0;
}
本文介绍了一种使用线段树解决村庄破坏与修复问题的方法,包括线段树的构建、更新和查询操作,适用于多案例场景。
2320

被折叠的 条评论
为什么被折叠?



