POJ 2528 Mayor's posters

题目大意

有 T 组数据,每组数据有一个 N 表示有 N 个人一次贴海报
然后 N 对 \(L_i\ R_i\) 表示一张海报的范围,问最后能看见多少张海报
数据范围:\(n\le 10000\ \ L_i\ R_i\le 10^7\)

题解

(开始英语不好看不懂题折腾了半天)
可以看出是线段树区改裸题
但是\(L_i\ R_i\le 10^7\) ,直接改会\(TLE\)
所以要离散化。
于是 \(Sort+Unique+LowerBound\)(这题肯定要把\(L_i\ \ R_i\)一起离散)
但是要注意:设离散化数组为\(X\)但存在\(X_i-X_{i-1}>1\)时,要加入一个元素\(X_{new}\)使得\(X_{i-1}<X_{new}<X_i\)
不然的话,这两张海报中间其实是有间隙的,但离散化后就省去了
为了方便可以先插入到最后然后排序。线段树部分不做阐述

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char buf[100000],*L=buf,*R=buf;
inline char Gc() {
	return L==R&&(R=(L=buf)+fread(buf,1,100000,stdin),L==R)?EOF:*L++;
}
inline int Rd() {
	register int o=0;
	char c=Gc();
	for(;c<'0'||c>'9';c=Gc()) ;
	for(;c>'/'&&c<':';c=Gc())o=(o<<1)+(o<<3)+(c^48);
	return o;
}
void Write(int o) {
	if(o>9)Write(o/10);
	putchar(o%10+48);
}
int T,n,tot,cnt,ans,l[20005],r[20005],x[80005];
int cl[320005],vis[320005];
inline void Dw(int rt) {
	if(!cl[rt])return;
	cl[rt<<1]=cl[rt<<1|1]=cl[rt];
	cl[rt]=0;
}
void Chan(int ql,int qr,int vl,int l,int r,int rt) {
	if(ql<=l && r<=qr) {
		cl[rt]=vl;
		return;
	}
	Dw(rt);
	register int mid=l+r>>1;
	if(ql<=mid)Chan(ql,qr,vl,l,mid,rt<<1);
	if(qr>mid)Chan(ql,qr,vl,mid+1,r,rt<<1|1);
}
void Query(int l,int r,int rt) {
	if(cl[rt]) {
		if(!vis[cl[rt]])
			++ans,vis[cl[rt]]=1;
		return;
	}
	if(l==r)return;
	register int mid=l+r>>1;
	Query(l,mid,rt<<1);
	Query(mid+1,r,rt<<1|1);
}
int main() {
	T=Rd();
	while(T--) {
		n=Rd(),tot=ans=0;
		memset(vis,0,sizeof(vis));
		memset(cl,0,sizeof(cl));
		for(int i=1;i<=n;i++) {
			l[i]=Rd(),r[i]=Rd();
			x[++tot]=l[i],x[++tot]=r[i];
		}
		sort(x+1,x+tot+1);
		cnt=unique(x+1,x+tot+1)-x-1;
		int ttt=cnt;
		for(int i=2;i<=ttt;i++)
			if(x[i]-x[i-1]>1)x[++cnt]=x[i-1]+1;
		sort(x+1,x+cnt+1);
		for(int i=1,rx,ry;i<=n;i++) {
			rx=lower_bound(x+1,x+cnt+1,l[i])-x;
			ry=lower_bound(x+1,x+cnt+1,r[i])-x;
			Chan(rx,ry,i,1,cnt,1);
		}
		Query(1,cnt,1);
		Write(ans);
		putchar(10);
	}
}
原文地址:https://www.cnblogs.com/KonjakLAF/p/14151549.html