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 }
所谓人生,一半惊喜,一半遗憾