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

自闭症网瘾萝莉.ら 提交于 2020-02-23 01:38:18

Mayor’s posters POJ - 2528

题意:
n(n<=10000) 个人依次贴海报,给出每张海报所贴的范围li 、ri(1<=li<=ri<=10000000)。求出最后还能看见多少张海报。

思路:
线段树区间更新题,可以用懒人更新的思路优化,对于线段树来说10000000显然太大,数组开不了,而n只有10000,就可以离散化一下。
但是离散化对本题来说有一个问题(坑), 就是由于我们是紧紧挨着压缩的, 所以可能会存在错误覆盖的问题
例如对于数据
3
1 10
1 3
7 10
我们压缩过后应该就变为
1 4
1 2
3 4
可这样的话我们目测一下, 就只有2个区间可以看到了, 第一个被盖住了. 而真正的答案应该是3才对
这是我们应该在离散化数组c中存储时考虑将每次的右边界r+1也存入, 这样就可以有效避免错误覆盖的问题。

问题code:

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int st[maxn * 4], vis[maxn * 2], cnt[maxn * 2], a[maxn * 2];
int ans;

void pushdown(int o){     //懒人更新 

	if(st[o]) st[o << 1] = st[o << 1 | 1] = st[o], st[o] = 0;

}

void updata(int o, int l, int r, int L, int R,int res){
	if(l >= L && r <= R){
		st[o] = res;
		return;
	}
	int m = (l + r) >> 1;
	pushdown(o);
	if(L <= m) updata(o << 1, l, m, L, R, res);
	if(R > m) updata(o << 1 | 1, m + 1, r, L, R, res);
}

void query(int o, int l, int r){
	if(st[o]) {
	    if(!vis[st[o]] && st[o] != 0){
		   vis[st[o]] = 1;
		   ans++;
		} 
		return;
	}
	if(l == r) return ;
	int m = (l + r) >> 1;
	pushdown(o);
	query(o << 1, l, m);
	query(o << 1 | 1, m + 1, r);
}
int main(){
	int c, n;
	scanf("%d", &c);
	while(c--){
	    scanf("%d", &n);
	    int cot = 0; 
		for(int i = 0; i < n; i++){
			scanf("%d%d", &cnt[i * 2], &cnt[i * 2 + 1]);
			a[cot++] = cnt[i * 2];
			a[cot++] = cnt[i * 2 + 1];
			a[cot++] = cnt[i * 2 + 1] + 1;
		} 
		sort(a, a + cot); 
		int tot = (int)(unique(a, a + cot) - a);  //unique函数返回值为第一个重复元素的指针
		for(int i = 0; i < 2 * n; i++)
		cnt[i] = (int)(lower_bound(a, a + cot, cnt[i]) - a + 1);
		
		ans = 0;                               //初始化 
		fill(vis, vis + 2 * tot + 1, 0);
		fill(st, st + 4 * tot + 1, 0);
		
		for(int i = 0; i < n; i++){
			updata(1, 1, tot, cnt[i * 2], cnt[i * 2 + 1], i + 1);
		
		}
		
		query(1, 1, tot);
		
		printf("%d\n", ans);
			
	}
}

正确code:

#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lc p<<1,s,mid
#define rc p<<1|1,mid+1,e
#define mid ((s+e)>>1)
#define CLR(A) memset(A,0,sizeof(A))
using namespace std;
 
const int N = 20005;
int col[N * 4], vis[N];
int le[N], ri[N], c[N * 2], ans;
 
void pushdown(int p)
{
    if(col[p] == -1) return;
    col[p << 1] = col[p << 1 | 1]  = col[p];
    col[p] = -1;
}
 
void update(int p, int s, int e, int l, int r, int v)
{
    if(s >= l && e <= r)
    {
        col[p] = v;
        return;
    }
    pushdown(p);
    if(l <= mid) update(lc, l, r, v);
    if(r > mid) update(rc, l, r, v);
}
 
void query(int p, int s, int e)
{
    if(col[p] != -1)
    {
        if(!vis[col[p]])
            vis[col[p]] = 1, ++ans;
        return;
    }
    query(lc);
    query(rc);
}
 
int compress(int n) //离散化
{
    int k = 0;
    for(int i = 0; i < n; ++i)
    {
        c[k++] = le[i];
        c[k++] = ri[i];
        c[k++] = ri[i] + 1;
    }
    sort(c, c + k);
    return unique(c, c + k) - c - 1;
}
 
int main()
{
    int cas, m, n, l, r;
    scanf("%d", &cas);
    while(cas--)
    {
        scanf("%d", &m);
        for(int i = 0; i < m; ++i)
            scanf("%d%d", &le[i], &ri[i]);
        n = compress(m);
    
        cout << "n = " << n << endl;
        
        
         ans = 0;
        CLR(col), CLR(vis);
        for(int i = 0; i < m; ++i)
        {
            l = lower_bound(c, c + n, le[i]) - c + 1;
            r = lower_bound(c, c + n, ri[i]) - c + 1;
            update(1, 1, n, l, r, i + 1);
        }
        vis[0] = 1;
        query(1, 1, n);
        printf("%d\n", ans);
    }
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!