您的位置:首页 > 理论基础 > 数据结构算法

hdu 4831(线段树---待解决)

2016-05-18 20:44 411 查看

Scenic Popularity

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

[align=left]Problem Description[/align]
  临近节日,度度熊们最近计划到室外游玩公园,公园内部包括了很多的旅游景点区和休息区,由于旅游景点很热门,导致景点区和休息区都聚集了很多人。所以度度熊在旅游之前想通过百度地图查看一下公园内各个地方的热门程度。

  假设所有景点区和休息区都是X轴直线上的一系列顶点,所对应的坐标Xi 保证唯一。每个景点区有个初始的热度值,而一个休息区(坐标为Xi)的热度值等于离它距离最近的景点区Xj的热度值(距离定义为|Xi-Xj|),如果此休息区与两个景点区的距离一样,则休息区的热度值选择两个景点区中的热度值最大值,如果两个热度值都一样,则随意选择其中一个。

  度度熊在出门之前会经常去查看百度地图,每次查看前会有某些景点区的热度值已发生改变,从而也会导致周围的休息区的热度值发生改变,然后度度熊想知道当前热度值<=Rk的顶点(包括景点区和休息区)有多少个
 

[align=left]Input[/align]
  输入数据的第一行是测试Case的个数(T<=100)。

  每个Case的第一行是N(0<N<=10000),表示景点区和休息区的总数。

  接着会有N行数据,每一列首先是顶点的X坐标Xi (0< Xi <=1e8),第二列是一个整数Hi(0=<Hi <=100000),如果Hi 不为0,则表示当前顶点为风景区且初始的热度值为Hi,否则表示当前顶点为休息区。这N行数据会按照坐标Xi递增的方式依次给出。

  接着的一行数据是操作的次数K(K<=100),最后会有K行数据,每一行的第一列要么是’U’或者’Q’,’U’表示当前操作为更改热度操作,’Q’表示当前操作为查询操作。如果是更改操作,接着会有两列数据,分别是热度值要改变的风景区的下标Lk(0<=Lk<N)以及改变后的热度值Vk(0< Vk<=100000);如果是查询操作,第二列是要查询的热度范围Rk(0< Rk<=100000)
 

[align=left]Output[/align]
  对于第k组测试数据,第一行输出Case #k:,接下来对每次查询操作(即Q操作)会输出一个整数,表示满足条件的顶点数有多少个
 

[align=left]Sample Input[/align]

1
4
10 0
20 3
30 0
40 2
3
Q 3
U 3 4
Q 3

 

[align=left]Sample Output[/align]

Case #1:
4
2

思路:首先可以用L[i]和R[i]记录休息区i的左边第一个景点和右边第一个景点,然后根据两边的距离选择休息区i的值为多少。接下来建立线段树,节点信息保存了该区间的最大值和最小值,查找时需要遍历整棵树,当然根据区间内的最值进行部分剪枝。修改时,可以根据L[i]和R[i]来找到该修改的景点左边和右边影响到的最远休息区l和r,接下来就是线段树的更新操作更新区间[l,r]的值了。感觉思路是这样的,但不知道为什么WA了,调了一天都没有发现哪里错了。。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 10005;
const int inf = 0x7fffff;
struct Segment
{
int l,r;
int Max,Min,lazy;
}tree[maxn<<2];
struct Node
{
int x,h;
}pos[maxn];
int n,m,L[maxn],R[maxn],belong[maxn];

void build(int rt,int l,int r)
{
tree[rt].l = l, tree[rt].r = r;
tree[rt].Max = tree[rt].lazy = 0;
tree[rt].Min = inf;
if(l == r)
{
tree[rt].Max = tree[rt].Min =  pos[belong[l]].h;
return;
}
int mid = (l + r) >> 1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
tree[rt].Max = max(tree[rt<<1].Max,tree[rt<<1|1].Max);
tree[rt].Min = min(tree[rt<<1].Min,tree[rt<<1|1].Min);
}

void PushDown(int rt)
{
if(tree[rt].lazy != 0)
{
tree[rt<<1].Max = tree[rt].Max;
tree[rt<<1].Min = tree[rt].Min;
tree[rt<<1].lazy = tree[rt].lazy;
tree[rt<<1|1].Max = tree[rt].Max;
tree[rt<<1|1].Min = tree[rt].Min;
tree[rt<<1|1].lazy = tree[rt].lazy;
tree[rt].lazy = 0;
}
}

void update(int rt,int l,int r,int val)
{
if(l <= tree[rt].l && tree[rt].r <= r)
{
tree[rt].Max = val;
tree[rt].Min = val;
tree[rt].lazy = val;
return;
}
PushDown(rt);
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(l <= mid) update(rt<<1,l,r,val);
if(mid < r) update(rt<<1|1,l,r,val);
tree[rt].Max = max(tree[rt<<1].Max,tree[rt<<1|1].Max);
tree[rt].Min = min(tree[rt<<1].Min,tree[rt<<1|1].Min);
}

int query(int rt,int val)
{
if(tree[rt].Max <= val)
return tree[rt].r - tree[rt].l + 1;
if(tree[rt].l == tree[rt].r || tree[rt].Min > val) return 0;
PushDown(rt);
int sum = 0;
sum += query(rt<<1,val);
sum += query(rt<<1|1,val);
return sum;
}

void init()
{
int cur = -1;
for(int i = 1; i <= n; i++)
{
L[i] = R[i] = i;
belong[i] = i;
}
for(int i = 1; i <= n; i++)	//找到往左走的第一个景点
{
if(pos[i].h != 0) cur = i;
else L[i] = cur;
}
cur = n + 1;
for(int i = n; i >= 1; i--)	//找到往右走的第一个景点
{
if(pos[i].h != 0) cur = i;
else R[i] = cur;
}
for(int i = 1; i <= n; i++)	//通过左边与右边的最近景点判断该休息区最开始属于哪个景点
{
if(L[i] == -1)
{
belong[i] = R[i];
continue;
}
if(R[i] == n + 1)
{
belong[i] = L[i];
continue;
}
if(pos[i].x - pos[L[i]].x < pos[R[i]].x - pos[i].x)
belong[i] = L[i];
else if(pos[i].x - pos[L[i]].x > pos[R[i]].x - pos[i].x)
belong[i] = R[i];
else
{
if(pos[L[i]].h >= pos[R[i]].h)
belong[i] = L[i];
else belong[i] = R[i];
}
}
}

int findLeft(int u)  //修改了u景点,最左能够影响到的休息区
{
if(u == 1 || pos[u].h != 0 && pos[u - 1].h != 0) return u;
int i = u - 1;
if(L[i] == -1) return 1;
while(pos[i].x - pos[L[i]].x > pos[R[i]].x - pos[i].x && pos[i].h == 0) i--; //必须找两个景点之间的休息区
if(pos[i].h != 0) return i + 1; //遍历到了景点
else if(pos[i].x - pos[L[i]].x < pos[R[i]].x - pos[i].x) return i + 1;
else if(pos[i].x - pos[L[i]].x == pos[R[i]].x - pos[i].x)
{
if(pos[L[i]].h <= pos[R[i]].h)
return i;
else return i + 1;
}
}

int findRight(int u)  //修改了u景点,最右能够影响到的休息区
{
if(pos[u].h != 0 && pos[u + 1].h != 0 || u == n) return u;
int i = u + 1;
if(R[i] == n + 1) return n;
while(pos[i].x - pos[L[i]].x < pos[R[i]].x - pos[i].x && pos[i].h == 0) i++;
if(pos[i].h != 0) return i - 1;
else if(pos[i].x - pos[L[i]].x > pos[R[i]].x - pos[i].x) return i - 1;
else if(pos[i].x - pos[L[i]].x == pos[R[i]].x - pos[i].x)
{
if(pos[L[i]].h >= pos[R[i]].h)
return i;
else return i - 1;
}
}

int main()
{
int t,u,v,cas = 1;
char str[2];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d%d",&pos[i].x,&pos[i].h);
init();
build(1,1,n);
scanf("%d",&m);
printf("Case #%d:\n",cas++);
while(m--)
{
scanf("%s",str);
if(str[0] == 'Q')
{
scanf("%d",&v);
printf("%d\n",query(1,v));
}
else if(str[0] == 'U')
{
scanf("%d%d",&u,&v);
u++;
pos[u].h = v;
int l = findLeft(u);
int r = findRight(u);
update(1,l,r,v);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构