51Nod 1672 扫描线 + 线段树/树状数组
2017-12-25 21:03
330 查看
题目大意,给定n个数字和m个区间,和k≤m,从m个区间中选出恰好k个,使得他们的交的和最大,数字都是正数,n,m,k<=1e5。
题解:首先不难发现这个题没法直接做,STL上了个错的思想,即每个区间都+1然后对于被覆盖了k+次的区间做最大字段和,显然是错的。
考虑枚举答案的右端点,显然左端点越远越不可能是答案,而左端点越远效果越好。并且注意到一个区间是覆盖[l,r]当且仅当这个区间既覆盖l,又覆盖r。这样每次r+1,就把不覆盖r的区间删去,把覆盖了r的区间加上。然后考虑左端点,如果左端点被少于k个区间覆盖,那么l++。
最后用所有的合法的[l,r]更新答案即可,上述可用线段树或者树状数组实现,由于每个区间只会被计算一次,所以复杂度O(nlgn).
考试的时候多组数据。
题解:首先不难发现这个题没法直接做,STL上了个错的思想,即每个区间都+1然后对于被覆盖了k+次的区间做最大字段和,显然是错的。
考虑枚举答案的右端点,显然左端点越远越不可能是答案,而左端点越远效果越好。并且注意到一个区间是覆盖[l,r]当且仅当这个区间既覆盖l,又覆盖r。这样每次r+1,就把不覆盖r的区间删去,把覆盖了r的区间加上。然后考虑左端点,如果左端点被少于k个区间覆盖,那么l++。
最后用所有的合法的[l,r]更新答案即可,上述可用线段树或者树状数组实现,由于每个区间只会被计算一次,所以复杂度O(nlgn).
考试的时候多组数据。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> #define N 100010 #define lint long long using namespace std; struct segment{ int s,l,r,pt; segment *ch[2]; }*rt; inline int update_tags(segment* &rt,int v) { return rt->pt+=v,rt->s+=v; } inline int push_down(segment* &rt) { update_tags(rt->ch[0],rt->pt); update_tags(rt->ch[1],rt->pt); return rt->pt=0; } int build(segment* &rt,int l,int r) { rt=new segment;rt->l=l,rt->r=r; rt->s=rt->pt=0;if(l==r) return 0; int mid=(l+r)>>1; build(rt->ch[0],l,mid); build(rt->ch[1],mid+1,r); return 0; } int Clear(segment* &rt) { rt->s=rt->pt=0;if(rt->l==rt->r) return 0; Clear(rt->ch[0]),Clear(rt->ch[1]);return 0; } int update(segment* &rt,int s,int t,int v) { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(s<=l&&r<=t) return update_tags(rt,v); if(rt->pt) push_down(rt); if(s<=mid) update(rt->ch[0],s,t,v); if(mid<t) update(rt->ch[1],s,t,v); return 0; } int query(segment* &rt,int p) { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(l==r) return rt->s; if(rt->pt) push_down(rt); if(p<=mid) return query(rt->ch[0],p); else return query(rt->ch[1],p); } int a ;lint s ,ans; vector<int> L ,R ; int main() { int n,k,m;build(rt,1,N); while(scanf("%d%d%d",&n,&k,&m)!=EOF) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i]; for(int i=1;i<=n;i++) L[i].clear(),R[i].clear(); Clear(rt);ans=0LL; for(int i=1;i<=m;i++) { int s,t;scanf("%d%d",&s,&t); L[s].push_back(t),R[t].push_back(s); } for(int r=1,l=1;r<=n;r++) { for(int i=0;i<R[r-1].size();i++) update(rt,R[r-1][i],r-1,-1); for(int i=0;i<L[r].size();i++) update(rt,r,L[r][i],1); while(l<=r&&query(rt,l)<k) l++; if(l<=r) ans=max(ans,s[r]-s[l-1]); } printf("%lld\n",ans); } return 0; }
相关文章推荐
- 51NOD 1210 矩阵查询 【线段树/树状数组】
- 51nod(1081 字段求和)(dp、树状数组、线段树求法)
- 离散化 + 线段树(树状数组) + 线扫描法
- 51Nod-1711平均数(二分+树状数组|线段树)
- [NOIP模拟题][树状数组][线段树]
- HDU 1166 线段树模板&树状数组模板
- poj 2828 Buy Tickets(树状数组 | 线段树)
- 51NOD 1672 区间交 线段树
- 线段树(树状数组)hdu4267
- 线段树,树状数组基础
- HDU 1166 敌兵布阵(树状数组 or 线段树 单点修改 区间求和)
- 线段树 + 树状数组 【小谈】
- POJ 3468(树状数组 && 线段树)
- 【BZOJ1818】[Cqoi2010]内部白点 扫描线+树状数组
- hdu_2795_线段树入门_线段树由树状数组转坑原本数组模拟
- 【扫描线或树状数组】CSU 1335 高桥和低桥
- poj-3468 A Simple Problem with Integers(线段树,树状数组区间求和)
- 树状数组-线段树
- 【bzoj4785】[Zjoi2017]树状数组 线段树套线段树
- 1003 线段树树状数组区间覆盖