您的位置:首页 > 产品设计 > UI/UE

poj 2528 Mayor's posters 线段树+离散化 区间更新

2012-07-25 11:08 323 查看
线段树第三天,结果就这么个题重写了两遍才过

首先,题目中说的墙的长度是10000000,如果用这个长度建线段树,一定是超内存的,所以需要离散化,具体的就是对输入的点的坐标进行排序,然后算出他们分别是第几小,用这个第几大去替换原来的值就好,如 1,5,8 可以替换成1,2,3因为线段(1,5)和(1,8)的关系与(1,2)(1,3)其实是一样的

离散化之后,那么线段树的长度最多就是2*n 了

此题中,线段树节点记录当前区间能看到的海报值,如果当前区间能看到多张海报或者看不到,那么就取0,否则就是海报值

在update线段树的时候,如果遇到(L<=l&&R>=r) 则直接将该区间的sum值更新,否则,先push_down一下,然后再更新左右子树,这里的push_down就是把父节点的值赋给子节点,如果父节点为0则不操作,这样做的原因是:每次我们更新只是更新到区间而不是叶子,所以当我们要对一个已经更新过的区间的子区间进行更新时,必须把这个区间的信息往下传递,否则,他的子区间就算被更新了,他的值没变,依然代表整个区间内还是这个海报

query的时候,还得注意一个问题,就是一张海报可能在多个区间段内,因此得有个标记表示该海报应被算过了,f数组就是这个功能

找到sum值大于0的时候,如果该海报没被访问,就返回1,否则0,否则,如果找到叶子了,就直接返回,如果不是这些情况,就继续对左右子树进行query

以下是代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 20010;
int sum[MAX<<2];
bool f[MAX];
void push_down(int rt)
{
if(sum[rt])
{
sum[rt<<1] = sum[rt];
sum[rt<<1|1] = sum[rt];
sum[rt] = 0;
}
}
void build(int l,int r,int rt)
{
if(l==r) return;
int mid = l+r>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
void update(int p,int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
sum[rt] = p;
return;
}
int mid = r+l>>1;
push_down(rt);
if(L<=mid) update(p,L,R,l,mid,rt<<1);
if(R>mid) update(p,L,R,mid+1,r,rt<<1|1);
}
int query(int L,int R,int l,int r,int rt)
{
if(sum[rt])
{
if(!f[sum[rt]])
{
f[sum[rt]] = 1;
return 1;
}
return 0;
}
if(l==r) return 0;
int mid = r+l>>1;
int ans = 0;
if(L<=mid) ans+=query(L,R,l,mid,rt<<1);
if(R>mid) ans+=query(L,R,mid+1,r,rt<<1|1);
return ans;
}
struct point //这是为了离散化用的
{
int x,y;
}p[MAX];
int cmp(const point &a,const point &b)
{
if(a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}
int x[MAX]; //离散化的结果,即p[i].x是第几小
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0; i<n*2; i++)
{
scanf("%d",&p[i].x);
p[i].y = i;
}
sort(p,p+n*2,cmp);
int cnt = 1;
int now = p[0].x;
x[p[0].y] = 1;
for(int i=1; i<n*2; i++)
{
if(p[i].x==now) x[p[i].y] = cnt;
else
{
x[p[i].y] = ++cnt;
now = p[i].x;
}
}
//上面是离散化
build(1,cnt,1);
memset(sum,0,sizeof(sum));
memset(f,0,sizeof(f));
for(int i=0; i<n; i++)
update(i+1,x[i<<1],x[i<<1|1],1,cnt,1);
printf("%d\n",query(1,cnt,1,cnt,1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  query build struct