【学习笔记】NOIP暴零赛4

escape

首先如果规定每个人都必须出去的话,那么直接按 a i + b i a_i+b_i ai+bi排序,从前往后扫一遍即可。

然后我直接贪心。wa了,和答案差的很远,然后换成按 a i a_i ai排序,恰好过了大样例。至此离正解越来越远

我真傻,真的,应该想到有反悔操作的。还是按 a i + b i a_i+b_i ai+bi从小到大排序,然后从前往后扫,如果当前这个人能对答案产生贡献,那么直接贪心的把它加进去;否则可以把已经加进去的数中 a i a_i ai最大的那个替换出来,不难证明因为此时将 a i + b i a_i+b_i ai+bi用较大值去替换较小值所以一定是合法的。用大根堆维护即可。

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int N=2e5+5;
int n,H,res;
ll S;
struct node{
	int a,b;
	bool operator <(const node &r)const{
		return a+b<r.a+r.b;
	}
}s[N];
priority_queue<int>q;
int main(){
	freopen("escape.in","r",stdin);
	freopen("escape.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;for(int i=1;i<=n;i++)cin>>s[i].a>>s[i].b;
	cin>>H;sort(s+1,s+1+n);for(int i=1;i<=n;i++)S+=s[i].a;
	for(int i=1;i<=n;i++){
		if(S+s[i].b>=H)res++,q.push(s[i].a),S-=s[i].a;
		else if(q.size()&&q.top()>s[i].a){
			S+=q.top()-s[i].a,q.pop(),q.push(s[i].a);
		}
	}cout<<res;
}

umi

原题是 「CF1209G2」Into Blocks (hard version)

作为一道数据结构题,个人认为它的思维量还是比较高的。

当然,我考场上并没有想到线段树,也没有口胡出正解,只想到了基于分治的单次 O ( n log ⁡ n ) O(n\log n) O(nlogn)的做法,可惜的是并不能恰好解决带修改的情况。

正解非常脑洞 确实是这样的 。考虑 b i b_i bi记录同时包含 i i i i + 1 i+1 i+1的区间的个数,显然最后会分成若干个不相交的区间,那么我们找那些 b i = 0 b_i=0 bi=0的点,对于每一段连续的 0 0 0,从这一段 0 0 0的开头到前一段 0 0 0结尾的后一个位置构成了一个区间,这段区间的颜色出现次数最大值显然就是对答案的贡献。

这玩意显然只能想到用线段树维护。对于两个相邻的 0 0 0我们要算区间众数,这里有一个非常聪明的想法,因为这个众数肯定都落在 [ l , r ] [l,r] [l,r]这个区间内,那么我们可以把某个颜色的出现次数放在其最左边的那个位置上,这样就变成了单点修改,并且可以把之前打的标记覆盖掉,可以很好的解决众数出现次数减少的情况。

注意一个坑点,这里的 0 0 0要当作区间最小值来维护。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int N=4e5+5;
int n,m,a[N],lsh[N],cnt;
int ps[N],c[N];
set<int>s[N];
int get(int x){
    return lower_bound(lsh+1,lsh+1+cnt,x)-lsh;
}
struct node{
	int s,ls,rs,min,max,tag;
}t[N<<2];
void work(int p,int x){
	t[p].min+=x,t[p].tag+=x;
}
void pushdown(int p){
	if(t[p].tag){
		work(p<<1,t[p].tag),work(p<<1|1,t[p].tag),t[p].tag=0;
	}
}
void pushup(int p){
	t[p].min=min(t[p<<1].min,t[p<<1|1].min);
	t[p].max=max(t[p<<1].max,t[p<<1|1].max);
	if(t[p<<1].min>t[p<<1|1].min){
		t[p].s=t[p<<1|1].s,t[p].ls=max(t[p<<1].max,t[p<<1|1].ls),t[p].rs=t[p<<1|1].rs;
	}
	else if(t[p<<1].min==t[p<<1|1].min){
		t[p].s=t[p<<1].s+t[p<<1|1].s+max(t[p<<1].rs,t[p<<1|1].ls),t[p].ls=t[p<<1].ls,t[p].rs=t[p<<1|1].rs;
	}
	else{
		t[p].s=t[p<<1].s,t[p].ls=t[p<<1].ls,t[p].rs=max(t[p<<1].rs,t[p<<1|1].max);
	}if(p==1)t[p].s+=t[p].ls;
}
void upd(int p,int l,int r,int ql,int qr,int x){
	if(ql>qr)return;
	if(ql<=l&&r<=qr){
		work(p,x);
		return;
	}
	int mid=l+r>>1;pushdown(p);
	if(ql<=mid)upd(p<<1,l,mid,ql,qr,x);
	if(mid<qr)upd(p<<1|1,mid+1,r,ql,qr,x);
	pushup(p);
}
void upd2(int p,int l,int r,int x,int y){
	if(l==r){
		t[p].ls=t[p].rs=t[p].max=y;
		return;
	}int mid=l+r>>1;pushdown(p);
	x<=mid?upd2(p<<1,l,mid,x,y):upd2(p<<1|1,mid+1,r,x,y);
	pushup(p);
}
void ins(int i){
	if(s[i].size()){
		int L=*s[i].begin(),R=*--s[i].end();
		upd(1,1,n,L,R-1,1),upd2(1,1,n,L,s[i].size());
	}
}
void del(int i){
	if(s[i].size()){
		int L=*s[i].begin(),R=*--s[i].end();
		upd(1,1,n,L,R-1,-1),upd2(1,1,n,L,0);
	}
}
void change(int x,int y){
	if(a[x]!=y){
		del(y),del(a[x]),s[y].insert(x),s[a[x]].erase(x),ins(y),ins(a[x]);
		a[x]=y;
	}	
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i],lsh[++cnt]=a[i];
	for(int i=1;i<=m;i++){
		cin>>ps[i]>>c[i],lsh[++cnt]=c[i];
	}sort(lsh+1,lsh+1+cnt),cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;
	for(int i=1;i<=n;i++)a[i]=get(a[i]),s[a[i]].insert(i);
	for(int i=1;i<=cnt;i++){
		if(s[i].size()){
			ins(i);
		}
	}cout<<n-t[1].s<<"\n";
	for(int i=1;i<=m;i++){
		c[i]=get(c[i]);
		int x=a[ps[i]];
		change(ps[i],c[i]),cout<<n-t[1].s<<"\n";
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值