由于题面中给定的wall最大长度为10 000 000;若简单用线段树势必会超时。
而注意到题面中规定了输入海报的个数<=1000;因此不妨离散化,使得线段中叶节点仅含有1000个,那么线段最大深度为10,不会TLE。
同时在构造线段树的时候除了设置基本的长度变量l,r之外,
设置了一个新的变量kind用于储存当前线段的覆盖状态(=0表示没有覆盖或有多个覆盖;=1表示只有一个覆盖)。这样当计算最终状态时只需要对 遍历到的每一个kind不为0的线段 计数值加1。同时线段的搜索也在这里终止(因为若上层线段已经覆盖,那么下层必然也被覆盖,因而不需重复搜索)。
这是本题解题的关键,也是体现线段树结构特色的地方,值得好好品味,很轻巧的构造。
此外在解题中出现了两次bug:
1、sort()范围出错,由于是从1位置开始而非0位置,因此范围需要+1;
2、使用map报TLE,改为int数组后AC。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstdlib> #include<map> #include<cstring> #include<algorithm> using namespace std; //代码原本使用map来记录位置和编号的映射,但是TLE;改成int数组后就ac了。stl还是要慎用。 //编程思路:先想清楚算法,先实现数据结构,再写主函数 const int maxn=10000+5; struct line{ int l,r,kind;//这个kind的记录是精华 }tree[maxn*10];//这个数量的判定 (1000的叶子,最多10层,取最大值10*maxn) int l[maxn],r[maxn]; int poster[maxn*2];//记录海报的所有坐标,离散化 void build(int l,int r,int node){ tree[node].l=l,tree[node].r=r; if(l==r)return; int mid=(l+r)/2; build(l,mid,node*2); build(mid+1,r,node*2+1); } void update(int l,int r,int node,int k){ if(tree[node].l==l&&tree[node].r==r){ tree[node].kind=k;//完全覆盖 return; } if(tree[node].kind==k)return ; // if(tree[node].kind!=0){//这里的细微差别个人感觉没啥影响(包括上面一行是否有必要存在的问题) if(tree[node].kind!=0&&tree[node].kind!=k){ tree[node*2].kind=tree[node].kind; tree[node*2+1].kind=tree[node].kind; tree[node].kind=0; } if(r<=tree[node*2].r){ update(l,r,node*2,k); } else if(l>=tree[node*2+1].l){ update(l,r,node*2+1,k); } else{ update(l,tree[node*2].r,node*2,k); update(tree[node*2+1].l,r,node*2+1,k); } } int result=0; bool flag[maxn]; void cal(int node){ if(tree[node].kind!=0){ if(flag[tree[node].kind]==false){ result++; // cout<<tree[node].l<<" "<<tree[node].r<<" "<<tree[node].kind<<endl;//test flag[tree[node].kind]=true; } } else{ cal(node*2); cal(node*2+1); } } int pos2no[10000005] ; int main(void){ int t; scanf("%d",&t); while(t--){ memset(tree,0,sizeof(tree)); memset(flag,false,sizeof(flag)); memset(poster,0,sizeof(poster)); memset(pos2no,0,sizeof(pos2no)); int n; scanf("%d",&n); int j=0; for(int i=1;i<=n;i++){//从1开始编号 scanf("%d%d",&l[i],&r[i]); poster[++j]=l[i];poster[++j]=r[i]; } sort(poster+1,poster+j+1);//排序去重 ;注意为什么是j+1 (wa点) int len=j,k=1; for(int i=1;i<=len;i++,k++){ poster[k]=poster[i]; while(poster[i]==poster[i+1])i++; } int finlen=k-1; //map<int,int> pos2no;//位置到编号的映射 若使用map也是正确的,但是会报TLE,故弃之。 for(int i=1;i<=finlen;i++){ pos2no[poster[i]]=i; } build(1,finlen,1) ; for(int i=1;i<=n;i++){ update(pos2no[l[i]],pos2no[r[i]],1,i); } result=0; cal(1); printf("%d\n",result); } return 0; }