第三次作业
639.线段树-贴海报 (10分)
C时间限制:3000 毫秒 | C内存限制:3000 Kb
题目内容:
由10^7块1x1的玻璃构成1x10^7的海报墙,每个海报完整地覆盖几块玻璃,海报的宽度可以不同。后来的人可以覆盖
前人的海报。一张海报如果有没被覆盖的部分,则称为可视海报。你的任务是找出有多少可视海报。
输入描述
第一行是测试的总数c,接下来的行是各测试用例。
每个测试的第一行是海报的总数n, n<=10000, 然后是n个按先后顺序贴的海报的位置li, ri. 满足1<=li<=ri<=10^7。
输出描述
每个测试的可视海报数目
输入样例
1
5
1 4
2 6
8 10
3 4
7 10
输出样例
4
代码:
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; #define L(rt) (rt<<1) #define R(rt) (rt<<1|1) const int N = 1e5+10; int flag; struct Tree{ int l,r; bool vis; }tree[N<<2]; struct Point{ int id,x; }post[N<<2]; int cmp1(Point a,Point b){ return a.x<b.x; } int cmp2(Point a,Point b){ if(a.id == b.id) return a.x < b.x; return a.id >b.id; } void PushUp(int rt){ tree[rt].vis = tree[L(rt)].vis&&tree[R(rt)].vis; } void build(int L,int R,int rt){ tree[rt].l = L; tree[rt].r = R; tree[rt].vis = 0; if(tree[rt].l == tree[rt].r) return ; int mid = (L+R)>>1; build(L,mid,L(rt)); build(mid+1,R,R(rt)); } void query(int L,int R,int rt){ if(tree[rt].vis) return ; if(tree[rt].l ==L&& tree[rt].r==R){ tree[rt].vis = 1; flag=1; return ; } int mid = (tree[rt].l + tree[rt].r)>>1; if(R<=mid) query(L,R,L(rt)); else if(L>=mid+1) query(L,R,R(rt)); else{ query(L,mid,L(rt)); query(mid+1,R,R(rt)); } PushUp(rt); } int main(){ int t,n; cin>>t; while(t--){ scanf("%d",&n); for(int i=0;i<2*n;i+=2){ scanf("%d%d",&post[i].x,&post[i+1].x); post[i].id = post[i+1].id = i; } sort(post,post+2*n,cmp1); int tot = 0,pre = 0; for(int i=0;i<2*n;i++){ if(post[i].x == pre) post[i].x = tot; else{ pre = post[i].x; post[i].x = ++tot; } } build(1,2*n,1); sort(post,post+2*n,cmp2); int ans = 0; for(int i=0;i<2*n;i=i+2){ int l = post[i].x; int r = post[i+1].x; flag = 0; query(l,r,1); if(flag) ans++; } cout<<ans<<endl; } return 0; }