P2519 [HAOI2011]problem a(线段树优化dp+思维)

题目描述

一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)

输入输出格式

输入格式:

第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi

输出格式:

一个整数,表示最少有几个人说谎

输入输出样例

输入样例#1: 复制
3
2 0
0 2
2 2
输出样例#1: 复制
1

说明

100%的数据满足: 1≤n≤100000 0≤ai、bi≤n




题目的本质并不难,难点在于对题提转化上:

比如有一行告诉你,有a个比他大,有b个比他小,那也就是说,前a个比他的并且大小关系不缺定,后b个比他小并且大小关系不确定,他是从a+1到n-y这段区间的数字全相等,这是题目也就转化为了 给你m个区间,每个区间的价值为v,让你选不相交的区间使得得到的价值最大,

要点:同一个区间可能有多个,使用了map计数。同一个区间的个数不能超过区间的长度。



 1 #include"bits/stdc++.h"
 2 #define lson rt<<1,l,mid
 3 #define rson rt<<1|1,mid+1,r
 4 
 5 using namespace std;
 6 
 7 map<pair<int ,int >,int > mp;
 8 
 9 int tr[4000000];
10 struct aa
11 {
12   int l,r;
13   bool operator<(const aa b)const
14   {
15    return r==b.r?l<b.l:r<b.r;
16   }
17 }a[200000]; int tot;
18 
19 namespace segtree
20 {
21    int que(int rt,int l,int r,int L,int R)
22    {
23      if(L>R)return 0;
24     // cout<<l<<" "<<r<<endl;
25      if(L<=l&&r<=R)return tr[rt]; int mid=l+r>>1;
26 int res=-1;     if(L<=mid)res=max(res,que(rt<<1,l,mid,L,R));
27   if(R>mid)res=max(res,que(rt<<1|1,mid+1,r,L,R));
28        return res;
29    }
30    void upd(int rt,int l,int r,int pos,int v)
31    {
32     if(l==r){tr[rt]=max(tr[rt],v);return ;} int mid=l+r>>1;
33     if(pos<=mid)upd(lson,pos,v);else upd(rson,pos,v);
34     tr[rt]=max(tr[rt<<1],tr[rt<<1|1]);
35    }
36 
37 
38 }using namespace segtree;
39 
40 int dp[200000];
41 
42 int main()
43 {
44     int n; cin>>n;
45     for (int i=1;i<=n;i++)
46     {
47       int x,y;scanf("%d%d",&y,&x);if(x+y+1>n)continue;
48        if(!mp[make_pair(x+1,n-y)])
49        {
50          a[++tot].l=x+1,a[tot].r=n-y,mp[make_pair(x+1,n-y)]++;
51        }
52      else if(mp[make_pair(x+1,n-y)]<n-y-x-1+1)
53         mp[make_pair(x+1,n-y)]++;
54 
55     }
56     sort(a+1,a+1+tot);
57 
58     for (int i=1;i<=tot;i++)
59     {
60      dp[a[i].r]=max(dp[a[i].r],que(1,0,n,0,a[i].l-1)+mp[make_pair(a[i].l,a[i].r)]);//cout<<i<<endl;
61      upd(1,0,n,a[i].r,dp[a[i].r]);
62     }
63     int ans=0;
64     for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
65     cout<<n-ans;
66 
67 
68 
69 
70 
71 }
原文地址:https://www.cnblogs.com/zhangbuang/p/10498142.html