http://poj.org/problem?id=2528
题意:有一面空白的墙,然后在上面贴广告,新的广告会覆盖以前贴的广告。问最后墙上有多少能看到的广告。
思路:区间问题可以用Splay树,线段树等算法,由于广告的长度最大能到 10000000 但是广告的数量最多只有 10000 所以现对数据离散化,离散化的时候要在间隔大于 1 的两个点之间插入一个数,避免覆盖两端后中间的的也没了,例如数据:
1
3
2 4
1 2
4 5
如果离散化的时候不再 2 和 4 中间插入一个 3 的话,最后的结果就会变成 2。
线段树(94ms):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 40005;
struct Tree{
int l, r;
int val, lazy;
inline void SetTree(int l, int r, int val, int lazy){
this->l = l;
this->r = r;
this->val = val;
this->lazy = lazy;
}
};
struct Node{
int l, r;
};
int n, m;
Tree tr[maxn << 2];
Node node[maxn >> 1];
int ary[maxn];
int ary1[maxn];
int Find(int *ary, int l, int r, int val)
{
int mid = (l + r) >> 1;
if(ary[mid] == val){
return mid;
}else if(ary[mid] > val){
return Find(ary, l, mid, val);
}else{
return Find(ary, mid + 1, r, val);
}
}
void PushDown(int rt)
{
if(!tr[rt].lazy || tr[rt].l == tr[rt].r)
return ;
tr[rt << 1].val = tr[rt].lazy;
tr[rt << 1 | 1].val = tr[rt].lazy;
tr[rt << 1].lazy = tr[rt].lazy;
tr[rt << 1 | 1].lazy = tr[rt].lazy;
tr[rt].lazy = 0;
}
void BuildTree(int rt, int l, int r)
{
tr[rt].SetTree(l, r, 0, 0);
if(l == r)
return ;
int mid = (l + r) >> 1;
BuildTree(rt << 1, l, mid);
BuildTree(rt << 1 | 1, mid + 1, r);
}
void Updata(int rt, int l, int r, int val)
{
PushDown(rt);
if(tr[rt].l > r || tr[rt].r < l)
return ;
if(tr[rt].l >= l && tr[rt].r <= r){
tr[rt].val = val;
tr[rt].lazy = val;
return ;
}
Updata(rt << 1, l, r, val);
Updata(rt << 1 | 1, l, r, val);
return ;
}
bool res[maxn];
void Query(int rt)
{
PushDown(rt);
if(tr[rt].l == tr[rt].r){
res[tr[rt].val] = true;
}else{
Query(rt << 1);
Query(rt << 1 | 1);
}
}
int main()
{
int Test;
scanf("%d", &Test);
while(Test--){
scanf("%d", &m);
for(int i = 0; i < m; i++){
scanf("%d%d", &node[i].l, &node[i].r);
ary[i << 1] = node[i].l;
ary[i << 1 | 1] = node[i].r;
}
int len = (m << 1);
sort(ary, ary + len);
int temp = 0;
ary1[temp++] = ary[0];
for(int i = 1; i < len; i++){
if(ary[i] > ary[i - 1] + 1) //在间隔大于 1 的位置插入一个数
ary1[temp++] = ary[i - 1] + 1;
ary1[temp++] = ary[i];
}
len = temp;
temp = 0;
for(int i = 1; i < len; i++){ //离散化
if(ary1[i] == ary[temp])
continue;
ary[++temp] = ary1[i];
}
len = temp + 1;
BuildTree(1, 1, len);
memset(res, false, sizeof(res));
for(int i = 0; i < m; i++){
node[i].l = Find(ary, 0, len - 1, node[i].l) + 1;
node[i].r = Find(ary, 0, len - 1, node[i].r) + 1;
Updata(1, node[i].l, node[i].r, i + 1);
}
Query(1);
int ans = 0;
for(int i = 1; i <= m; i++){
ans += (res[i] == true);
}
printf("%d\n", ans);
}
return 0;
}
Splay(94ms):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 40005;
struct Tree{
int pre, chd[2];
int val, lazy, Size;
inline void SetTree(int pre, int chd0, int chd1, int val, int lazy, int Size){
this->pre = pre;
this->chd[0] = chd0;
this->chd[1] = chd1;
this->val = val;
this->lazy = lazy;
this->Size = Size;
}
};
struct Node{
int l, r;
};
int n, m;
Tree tr[maxn];
Node node[maxn >> 1];
int ary[maxn];
int ary1[maxn];
bool res[maxn];
void PushUp(int rt)
{
tr[tr[rt].chd[0]].pre = rt;
tr[tr[rt].chd[1]].pre = rt;
tr[rt].Size = tr[tr[rt].chd[0]].Size + tr[tr[rt].chd[1]].Size + 1;
}
void PushDown(int rt)
{
if(!tr[rt].lazy)
return ;
if(tr[rt].chd[0]){
tr[tr[rt].chd[0]].val = tr[rt].lazy;
tr[tr[rt].chd[0]].lazy = tr[rt].lazy;
}
if(tr[rt].chd[1]){
tr[tr[rt].chd[1]].val = tr[rt].lazy;
tr[tr[rt].chd[1]].lazy = tr[rt].lazy;
}
tr[rt].lazy = 0;
}
int F(int rt){
return tr[tr[rt].pre].chd[1] == rt;
}
void Rotate(int rt)
{
int chd = F(rt);
int pre = tr[rt].pre;
tr[rt].pre = tr[pre].pre;
tr[tr[pre].pre].chd[F(pre)] = rt;
tr[pre].chd[chd] = tr[rt].chd[!chd];
tr[rt].chd[!chd] = pre;
PushUp(pre);
PushUp(rt);
}
int Splay(int rt, int rw)
{
while(tr[rw].pre != rt){
int pre = tr[rw].pre;
if(F(rw) != F(pre) || tr[pre].pre == rt){
Rotate(rw);
}else{
Rotate(pre);
Rotate(rw);
}
}
if(rt)
PushUp(rt);
return rw;
}
int Serch(int rt, int pos)
{
int ret = rt;
PushDown(rt);
if(tr[tr[rt].chd[0]].Size == pos - 1){
ret = rt;
}else if(tr[tr[rt].chd[0]].Size >= pos){
ret = Serch(tr[rt].chd[0], pos);
}else{
ret = Serch(tr[rt].chd[1], pos - tr[tr[rt].chd[0]].Size - 1);
}
return ret;
}
void Query(int rt)
{
if(!rt)
return ;
PushDown(rt);
res[tr[rt].val] = true;
Query(tr[rt].chd[0]);
Query(tr[rt].chd[1]);
}
int BuildTree(int Size)
{
for(int i = 1; i < Size; i++){
tr[i].SetTree(i - 1, 0, i + 1, 0, 0, Size - i + 1);
}
tr[0].SetTree(0, 0, 0, 0, 0, 0);
tr[Size].SetTree(Size - 1, 0, 0, 0, 0, 1);
return 1;
}
int Find(int *ary, int l, int r, int val)
{
int mid = (l + r) >> 1;
if(ary[mid] == val){
return mid;
}else if(ary[mid] > val){
return Find(ary, l, mid, val);
}else{
return Find(ary, mid + 1, r, val);
}
}
int main()
{
int Test;
scanf("%d", &Test);
while(Test--){
scanf("%d", &m);
for(int i = 0; i < m; i++){
scanf("%d%d", &node[i].l, &node[i].r);
ary[i << 1] = node[i].l;
ary[i << 1 | 1] = node[i].r;
}
int len = (m << 1);
sort(ary, ary + len);
int temp = 0;
ary1[temp++] = ary[0];
for(int i = 1; i < len; i++){
if(ary[i] > ary[i - 1] + 1)
ary1[temp++] = ary[i - 1] + 1;
ary1[temp++] = ary[i];
}
len = temp;
temp = 0;
for(int i = 1; i < len; i++){
if(ary1[i] == ary[temp])
continue;
ary[++temp] = ary1[i];
}
len = temp + 1;
int rt = BuildTree(len + 2);
rt = Splay(0, len + 2);
memset(res, false, sizeof(res));
for(int i = 0; i < m; i++){
node[i].l = Find(ary, 0, len - 1, node[i].l) + 1;
node[i].r = Find(ary, 0, len - 1, node[i].r) + 1;
rt = Splay(0, Serch(rt, node[i].l));
Splay(rt, Serch(rt, node[i].r + 2));
tr[tr[tr[rt].chd[1]].chd[0]].val = i + 1;
tr[tr[tr[rt].chd[1]].chd[0]].lazy = i + 1;
}
Query(rt);
int ans = 0;
for(int i = 1; i <= m; i++){
ans += (res[i] == true);
}
printf("%d\n", ans);
}
return 0;
}