http://poj.org/problem?id=2528
题目大意:
贴海报 有先后顺序
会发生覆盖 问你最后漏在外面的有几张海报
思路:
1.所给数据范围比较大,而且是以块为单位 所以首先要离散化排序+把块变成线
2.建树
3.按所给海报顺序进行贴海报 解决覆盖问题
4.搜索一遍 看看有哪些海报是漏在外面的 统计数量
代码及其注释:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<queue> #include<set> using namespace std; const int N=10005; struct node1 { int l,r; }mem[N];//所给海报顺序 及其大小 struct node { int k; int l,r; }btree[N*10];//线段树 set<int>str; bool cansee[N];//是否漏在外面 int a[N*2]; int I; void build(int x,int i,int j)// 建树 { btree[x].k=-1; btree[x].l=i;//注意 l 不是直接表示左边界的大小范围 而是范围大小的下表 btree[x].r=j; if(i+1==j) return ; int mid=(i+j)>>1; build(x*2,i,mid); build(x*2+1,mid,j); } void place(int x,int k,int l,int r) { if(a[btree[x].l]==l&&a[btree[x].r]==r)//如果正好覆盖这一块则不用往下搜了 否则会超时 { btree[x].k=k; return ; } if(btree[x].k>0) { btree[x*2].k=btree[x].k;//对应上面的 本来是一个整块现在被破坏了 需要把数据向下传 btree[x*2+1].k=btree[x].k; btree[x].k=0; } int mid=a[(btree[x].l+btree[x].r)>>1]; if(l>=mid) { place(x*2+1,k,l,r); }else if(r<=mid) { place(x*2,k,l,r); }else { place(x*2,k,l,mid); place(x*2+1,k,mid,r); } } void find(int x)//最后搜一遍 并记录 { cansee[btree[x].k]=true; if(btree[x].l+1==btree[x].r||btree[x].k>0) return ; find(x*2); find(x*2+1); } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); str.clear(); for(int i=1;i<=n;++i) { scanf("%d %d",&mem[i].l,&mem[i].r); ++mem[i].r;//块变线 str.insert(mem[i].l);//用set自动 去重,排序 str.insert(mem[i].r); } I=0; for(set<int>::iterator t=str.begin();t!=str.end();++t) { ++I;a[I]=*t;//把set中的数据导入a数组中 } build(1,1,I);//建树 for(int i=1;i<=n;++i) { place(1,i,mem[i].l,mem[i].r);//贴海报 } memset(cansee,false,sizeof(cansee)); find(1);//搜索 int ans=0; for(int i=1;i<=n;++i) { if(cansee[i]) ++ans; } printf("%d\n",ans); } return 0; }