[BZOJ2298]problem a
Description
一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)
Input
第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi
Output
一个整数,表示最少有几个人说谎
Sample Input
3
2 0
0 2
2 2
2 0
0 2
2 2
Sample Output
1
HINT
100%的数据满足: 1≤n≤100000 0≤ai、bi≤n
首先我们考虑一下,撒谎的人去哪了
然后经过周密的推理分析,可以发现,他们爱去哪去哪跟我们半毛钱关系没有
所以我们直接不管他,一开始把不符合条件的直接判掉
然后对于一个人暂时符合条件的人,可以发现它跟其他人的人物关系可以表示成这样
红色表示和我一样的,黄色表示比我弱的,蓝色表示比我强的
可以发现“和我一样的”这个区间一定是不交的
然后我们就相当于要找一些不交的区间使个组最多
用线段树维护一下即可
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<map> 5 #define ls node<<1 6 #define rs node<<1|1 7 #define M 100010 8 using namespace std; 9 map<int,int>MP[M]; 10 int n,cnt,ans; 11 int f[M],val[M<<2]; 12 struct point{int l,r,v;}a[M]; 13 bool cmp(point a1,point a2) { 14 return a1.l<a2.l||(a1.l==a2.l&&a1.r<a2.r); 15 } 16 void insert(int node,int l,int r,int p,int v) { 17 val[node]=max(val[node],v); 18 if(l==r) return; 19 int mid=(l+r)/2; 20 if(p<=mid) insert(ls,l,mid,p,v); 21 else insert(rs,mid+1,r,p,v); 22 } 23 int query(int node,int l,int r,int l1,int r1) { 24 if(l1<=l&&r1>=r) return val[node]; 25 int mid=(l+r)/2,ans=0; 26 if(l1<=mid) ans=max(ans,query(ls,l,mid,l1,r1)); 27 if(r1>mid) ans=max(ans,query(rs,mid+1,r,l1,r1)); 28 return ans; 29 } 30 int main() { 31 scanf("%d",&n); 32 for(int i=1,l,r;i<=n;i++) { 33 scanf("%d%d",&l,&r);l=l+1,r=n-r; 34 if(l>r) continue; 35 if(!MP[l][r]) MP[l][r]=++cnt,f[cnt]++,a[cnt]=(point){l,r,0}; 36 else f[MP[l][r]]++; 37 } 38 for(int i=1;i<=cnt;i++) a[i].v=min(f[i],a[i].r-a[i].l+1); 39 sort(a+1,a+1+cnt,cmp); 40 for(int i=1;i<=cnt;i++) { 41 int t=0; 42 if(a[i].l>1) t=query(1,1,n,1,a[i].l-1); 43 insert(1,1,n,a[i].r,t+a[i].v); 44 ans=max(ans,t+a[i].v); 45 } 46 printf("%d\n",n-ans); 47 return 0; 48 }