题目链接:http://poj.org/problem?id=2528
题意:就是糊墙给你一面墙让你往上粘海报 粘到最后问你能看见几张
题解:知道了线段树这个玩意之后,看到这个题,就知道他可以用线段树来做,但是它这个点的分布范围太大了,而且线段树一般都是开四倍,内存超妥妥的,这应该怎么办呢?题目给出的样例只有一万组,这样的话可以用离散化的方法来搞这个题。啥叫离散化?就是把一段大区间存储的信息用一段小区间来表示。那这个题来说,当前数组下标代表的是真实坐标的一个映射,也就是这个坐标在这一堆坐标里排什么位置。具体处理方法看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
#define lson l,mid,fa<<1
#define rson mid+1,r,fa<<1|1
int a[100000];
int t[100000];
int ans[100000];
int laz[100000];
int coor[100000];
int f[2],num,st,ed,sum;
int se[100000];
void Add(int l,int r, int fa) {
if(laz[fa]) {
laz[fa<<1] = laz[fa];
laz[fa<<1|1] = laz[fa];
ans[fa] = laz[fa]*(r-l+1);
laz[fa] = 0;
}
}
void Update(int l,int r,int fa) {
if(st<=l&&r<=ed) {laz[fa] = num; return ;}
if(ed<l||r<st) return;
Add(l,r,fa);
int mid = (l+r)>>1;
Update(lson);Update(rson);
ans[fa] = num*(min(ed,r)-max(st,l)+1);
}
void Query(int l,int r, int fa) {
if (l==r) {
if(!se[ans[fa]+laz[fa]]){
sum++;
se[ans[fa]+laz[fa]] = 1;
}
return;
}
Add(l,r,fa);
int mid = (l+r)>>1;
Query(lson);Query(rson);
}
int main() {
int c; scanf("%d",&c);
while (c--) {
memset(ans,0,sizeof(ans));
memset(se,0,sizeof(se));
int n; scanf("%d",&n);
for (int i = 1; i <= n*2; i++) scanf("%d",&a[i]);
for (int i = 1; i <= n*2; i++) t[i] = a[i];
sort(t+1,t+n*2+1);
coor[1] = t[1];
int k = 2;
for (int i = 2; i <= n*2; i++)
if (t[i-1]<t[i]) coor[k++] = t[i];
for (int i = 1; i <= n; i++) {
for (int j = -1; j <= 0; j++) {
int tt = a[i*2+j];
int l = 1, r = k-1;
while(l<=r) {
int mid = (l+r)>>1;
if(coor[mid] == tt){f[1+j] = mid; break;}
else if(coor[mid]<tt) l = mid+1;
else r = mid -1;
}
}
num = i;st = f[0];ed = f[1];
Update(1,k-1,1);
}
sum = 0;
Query(1,k-1,1);
printf("%d\n",sum);
}
return 0;
}
原文:https://www.cnblogs.com/fengyuzhicheng/p/9236523.html