这两道题都是写完第一道题,用第一题的思路转化一下,第二题也能解决,所以放在一起整理
首先是第一题
在这里我就不再证明贪心了,只是直接的取最靠左的位置,这样是最优的(一开始我想的是取短的,后面发现可以hack掉,但是能拿80分)
直接贴代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
#define lc u<<1
#define rc u<<1|1
int a[N];
struct Tree{
int l,r,val,add;//这里直接维护的就是最小值
}tr[N*4];
struct node{
int x,y;
int dis;
bool operator<(const node&t) {return y<t.y;};
}nodes[N];
int n,m;
void pushdown(int u){
if(tr[u].add){
tr[lc].add+=tr[u].add;
tr[rc].add+=tr[u].add;
tr[lc].val+=tr[u].add;
tr[rc].val+=tr[u].add;
tr[u].add=0;
}
}
void pushup(int u){
tr[u].val=min(tr[lc].val,tr[rc].val);
}
void build(int u,int l,int r){
tr[u]={l,r,a[l],0};
if(l==r) return;
int m=(l+r)>>1;
build(lc,l,m);
build(rc,m+1,r);
pushup(u);
}
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u].val;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
int minn=1e9;
if(l<=m) minn=min(query(lc,l,r),minn);
if(r>m) minn=min(query(rc,l,r),minn);
return minn;
}
void update(int u,int l,int r,int k){
if(l<=tr[u].l&&tr[u].r<=r){
tr[u].val-=1;
tr[u].add+=k;
return;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
if(l<=m) update(lc,l,r,k);
if(r>m) update(rc,l,r,k);
pushup(u);
}
int main(){
//维护一颗线段树 直接维护区间最小值,然后每次update让他-1,如果这个最小值小于等于0就直接跳过
//排序的方法,从短到长且从前到后,贪心,一定最优
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=m;++i){
cin>>nodes[i].x>>nodes[i].y,nodes[i].dis=nodes[i].y-nodes[i].x;
}
sort(nodes+1,nodes+1+m);
build(1,1,n);
int ans=0;
for(int i=1;i<=m;++i){
if(query(1,nodes[i].x,nodes[i].y)>0){
update(1,nodes[i].x,nodes[i].y,-1);
ans++;
}
}
cout<<ans<<endl;
return 0;
}
第二道题思路差不多,要注意维护的区间右端减一就好,题解多是使用维护最大值的区间来计算,这里我用一个小二分+维护最小值也能做,贴一个维护最小值的代码
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int M=5e4+10;
#define lc u<<1
#define rc u<<1|1
struct Tree{
int l,r,sum,add;
}tr[M*4];
struct node{
int x,y,z;
bool operator<(const node &t)const{return y<t.y;};
}nodes[M];
int k,n,c;
void pushup(int u){
tr[u].sum=min(tr[lc].sum,tr[rc].sum);
}
void pushdown(int u){
if(tr[u].add){
tr[lc].sum+=tr[u].add;
tr[rc].sum+=tr[u].add;
tr[lc].add+=tr[u].add;
tr[rc].add+=tr[u].add;
tr[u].add=0;
}
}
void build(int u,int l,int r){
tr[u]={l,r,c,0};
if(l==r) return;
int m=(l+r)>>1;
build(lc,l,m);
build(rc,m+1,r);
pushup(u);
}
void update(int u,int l,int r,int k){
if(l<=tr[u].l&&tr[u].r<=r){
tr[u].add+=k;
tr[u].sum+=k;
return;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
if(l<=m) update(lc,l,r,k);
if(r>m) update(rc,l,r,k);
pushup(u);
}
int query(int u,int l,int r){
if(l<=tr[u].l&&tr[u].r<=r){
return tr[u].sum;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
int minn=1e9+10;
if(l<=m) minn=min(query(lc,l,r),minn);
if(r>m) minn=min(query(rc,l,r),minn);
return minn;
}
bool check(int x,int i){
if(query(1,nodes[i].x,nodes[i].y)<x) return false;
return true;
}
signed main(){
cin>>k>>n>>c;
build(1,1,n);
for(int i=1;i<=k;++i){
cin>>nodes[i].x>>nodes[i].y>>nodes[i].z;
nodes[i].y-=1;
}
//for(int i=1;i<=k;++i){
// cout<<nodes[i].x<<' '<<nodes[i].y<<' '<<nodes[i].z<<endl;
//}
//cout<<endl;
sort(nodes+1,nodes+1+k);
int ans=0;
for(int i=1;i<=k;++i){
int l=0,r=nodes[i].z+1;
while(l+1<r){
int m=(l+r)>>1;
if(check(m,i)) l=m;
else r=m;
}
update(1,nodes[i].x,nodes[i].y,-l);
//cout<<l<<endl;
ans+=l;
}
//cout<<endl;
//for(int i=1;i<=k;++i){
// cout<<nodes[i].x<<' '<<nodes[i].y<<' '<<nodes[i].z<<endl;
//}
//cout<<endl;
cout<<ans<<endl;
return 0;
}
总而言之,实现代码难度不大,重在思维,好像不用线段树也能做话说(,数据有点水