2019牛客暑期多校训练营(第一场)I Points Division(DP+线段树)

题目链接:https://ac.nowcoder.com/acm/contest/881/I

题目大意:

  给出n个点,每个点有a,b两个属性,让你从左下角到右上角划一条线,线的左边每个点的贡献是$a_{i}$,线的右边每个点的贡献是$b_{i}$,使得两部分的总和最大。即$max(\sum_{i\epsilon A}a_{i})+(\sum_{i\epsilon B}b_{i})$,且满足当$i\epsilon A$,$j\epsilon B$时,$x_{i}\geq x_{j}$和$y_{i}\leq y_{j}$。

解题报告:

  先对y坐标进行离散化,考虑这条线经过若干个B点,如果当前点要取a,那么之前比它低的点的贡献都为a,如果当前点要取b,那么之前比它高的点的贡献都为b,然后还要考虑对当前点的b是否要选,区间维护dp,采用线段树。

AC代码:

  1 #include<bits/stdc++.h>
  2 #define numm ch-48
  3 #define pd putchar(' ')
  4 #define pn putchar('\n')
  5 #define pb push_back
  6 #define fi first
  7 #define se second
  8 #define fre1 freopen("1.txt","r",stdin)
  9 #define fre2 freopen("3.txt","w",stdout)
 10 #define bug cout<<"*******************"<<endl;
 11 #define debug(args...) cout<<#args<<"->"<<args<<"\n";
 12 using namespace std;
 13 template <typename T>
 14 void read(T &res) {
 15     bool flag=false;char ch;
 16     while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
 17     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
 18     flag&&(res=-res);
 19 }
 20 template <typename T>
 21 void write(T x) {
 22     if(x<0) putchar('-'),x=-x;
 23     if(x>9) write(x/10);
 24     putchar(x%10+'0');
 25 }
 26 typedef long long ll;
 27 typedef unsigned long long ull;
 28 const int maxn=100010;
 29 const int maxm=505;
 30 const int mod=1e9+7;
 31 const int inv2=500000004;
 32 const int inf=0x3f3f3f3f;
 33 const ll INF=0x3f3f3f3f3f3f3f3f;
 34 const int N=32;
 35 struct node {
 36     int a,b,x,y;
 37     bool operator<(const node &z) {
 38         return x==z.x?y>z.y:x<z.x;
 39     }
 40 }p[maxn];
 41 struct ST {
 42     #define ls (k<<1)
 43     #define rs (k<<1|1)
 44     struct node {
 45         int l,r;
 46         ll maxx,lazy;
 47     }st[maxn<<2];
 48     void pushup(int k) {
 49         st[k].maxx=max(st[ls].maxx,st[rs].maxx);
 50     }
 51     void pushdown(int k) {
 52         st[ls].maxx+=st[k].lazy;
 53         st[ls].lazy+=st[k].lazy;
 54         st[rs].maxx+=st[k].lazy;
 55         st[rs].lazy+=st[k].lazy;
 56         st[k].lazy=0;
 57     }
 58     void build(int k,int l,int r) {
 59         st[k]=node{l,r,0,0};
 60         if(l==r) {
 61             st[k].maxx=-INF;
 62             st[k].lazy=0;
 63             return ;
 64         }
 65         int mid=(l+r)>>1;
 66         if(l<=mid) build(ls,l,mid);
 67         if(mid<r) build(rs,mid+1,r);
 68         pushup(k);
 69     }
 70     void add(int k,int l,int r,ll x) {   ///区间修改
 71         if(l>r) return ;
 72         if(st[k].l==l&&st[k].r==r) {
 73             st[k].maxx+=x;
 74             st[k].lazy+=x;
 75             return ;
 76         }
 77         if(st[k].lazy) pushdown(k);
 78         int mid=(st[k].l+st[k].r)>>1;
 79         if(mid>=r) add(ls,l,r,x);
 80         else if(mid<l) add(rs,l,r,x);
 81         else {
 82             add(ls,l,mid,x);
 83             add(rs,mid+1,r,x);
 84         }
 85         pushup(k);
 86     }
 87     void update(int k,int pos,ll x) {   ///单点修改进行取值最优化(dp)
 88         if(st[k].l==st[k].r) {
 89             st[k].maxx=max(st[k].maxx,x);
 90             return ;
 91         }
 92         if(st[k].lazy) pushdown(k);
 93         int mid=(st[k].l+st[k].r)>>1;
 94         if(mid>=pos) update(ls,pos,x);
 95         else if(mid<pos) update(rs,pos,x);
 96         pushup(k);
 97     }
 98     ll querymax(int k,int l,int r) {    ///区间查询
 99         if(l>r) return 0;
100         if(st[k].l==l&&st[k].r==r) return st[k].maxx;
101         if(st[k].lazy) pushdown(k);
102         int mid=(st[k].l+st[k].r)>>1;
103         if(mid>=r) return querymax(ls,l,r);
104         else if(mid<l) return querymax(rs,l,r);
105         else return max(querymax(ls,l,mid),querymax(rs,mid+1,r));
106     }
107 }wtz;
108 int t[maxn];
109 int main()
110 {
111 //    #define local
112     #ifdef local
113         fre1;
114         fre2;
115     #endif // local
116     int n,m;
117     while(scanf("%d",&n)!=EOF) {
118         int tot=0;
119         for(int i=1;i<=n;i++) {
120             read(p[i].x),read(p[i].y);
121             read(p[i].a),read(p[i].b);
122             t[++tot]=p[i].y;
123         }
124         sort(t+1,t+1+n);
125         tot=unique(t+1,t+1+n)-t-1;
126         for(int i=1;i<=n;i++)   ///离散化
127             p[i].y=lower_bound(t+1,t+1+tot,p[i].y)-t+1; ///线段树从1到p[i].y-1,p[i].y至少为2
128         sort(p+1,p+1+n);
129         tot++;  ///总区间加1,所以tot++
130         wtz.build(1,1,tot);
131         wtz.update(1,1,0);  ///新增高为0的点
132         for(int i=1;i<=n;i++) {
133             ll now=wtz.querymax(1,1,p[i].y);
134             wtz.update(1,p[i].y,now+p[i].b);
135             wtz.add(1,p[i].y+1,tot,p[i].b); ///对于当前点b选中的话,之前的比它高的都会被选
136             wtz.add(1,1,p[i].y-1,p[i].a);   ///对于当前点a选中的话,之前的比它低的都会被选
137         }
138         write(wtz.st[1].maxx);pn;
139     }
140     return 0;
141 }
代码在这里!

猜你喜欢

转载自www.cnblogs.com/wuliking/p/11372978.html
今日推荐