zoukankan      html  css  js  c++  java
  • [BJOI2019] 删数

    https://www.luogu.org/problemnew/show/P5324

    题解

    首先我们需要弄清这个答案是什么。

    对于一个长度为n的序列,那么它先删的肯定是(n),删完之后它就会跳到(n-cnt[n])位置,然后变成子问题继续做 。

    于是我们把每个数看做一条覆盖(n-cnt[n]+1 sim n)的一条线段,那么有解的前提是(1sim n)中的每个数都被覆盖了。

    如果没有,需要调整多少次呢?

    可以发现,我们可以花费一的代价将一条线段的长度-1,再将另一条线段长度+1,可以发现答案就是所有没有被覆盖的位置的长度和。

    然后用线段树完成这个操作,整体加的话就将询问区间平移,注意:右端点不在询问区间内的线段要清掉。

    代码

    #include<bits/stdc++.h>
    #define N 150009
    #define P pair<int,int>
    #define mm make_pair
    using namespace std;
    typedef long long ll;
    int tr[N*12],la[N*12],num[N*12],nowl,nowr,maxn,n,m,a[N],tag;
    map<int,int>tong;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    void build(int cnt,int l,int r){
    	num[cnt]=r-l+1;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	build(cnt<<1,l,mid);build(cnt<<1|1,mid+1,r); 
    }
    inline void pushdown(int cnt){
    	la[cnt<<1]+=la[cnt];
    	tr[cnt<<1]+=la[cnt];
    	la[cnt<<1|1]+=la[cnt];
    	tr[cnt<<1|1]+=la[cnt];
    	la[cnt]=0;
    }
    inline P merge(P x,P y){
    	P z=x;
    	if(y.first<z.first)z=y;
    	else if(y.first==z.first)z.second+=y.second;
    	return z;
    }
    inline void pushup(int cnt){
    	tr[cnt]=tr[cnt<<1];num[cnt]=num[cnt<<1];
    	if(tr[cnt<<1|1]<tr[cnt])tr[cnt]=tr[cnt<<1|1],num[cnt]=num[cnt<<1|1];
    	else if(tr[cnt<<1|1]==tr[cnt])num[cnt]+=num[cnt<<1|1];
    }
    P query(int cnt,int l,int r,int L,int R){
    	if(l>=L&&r<=R)return mm(tr[cnt],num[cnt]);
    	int mid=(l+r)>>1;
    	if(la[cnt])pushdown(cnt);
    	if(mid>=L&&mid<R)return merge(query(cnt<<1,l,mid,L,R),query(cnt<<1|1,mid+1,r,L,R));
    	if(mid>=L)return query(cnt<<1,l,mid,L,R);
    	if(mid<R)return query(cnt<<1|1,mid+1,r,L,R);
    }
    void upd(int cnt,int l,int r,int L,int R,int tag){
    	if(l>=L&&r<=R){
    		tr[cnt]+=tag; 
    	    la[cnt]+=tag;
    	    return;
    	}
    	int mid=(l+r)>>1;
    	if(la[cnt])pushdown(cnt);
    	if(mid>=L)upd(cnt<<1,l,mid,L,R,tag);
    	if(mid<R)upd(cnt<<1|1,mid+1,r,L,R,tag);
    	pushup(cnt);
    }
    inline void work(int l,int r,int tag){
    	l=max(l,nowl);r=min(r,nowr);
    	if(l>r)return; 
    	upd(1,1,maxn,l-nowl,r-nowl,tag);
    }
    int main(){
    	n=rd();m=rd();
    	nowl=1-m-1;nowr=n+m+1;
    	maxn=nowr-nowl+1;
    	build(1,1,maxn);
    	int ls=1,rs=n;
    	for(int i=1;i<=n;++i)a[i]=rd(),tong[a[i]]++;
    	for(int i=1;i<=n;++i)work(i-tong[i]+1,i,1);
    	int p,x;
    	while(m--){
    		p=rd();x=rd();
    		if(!p){
    			ls-=x;rs-=x;tag-=x;
    			if(x<0){
    				int xx=rs,yy=ls-1;
    				if(tong.find(xx)!=tong.end())work(xx-tong[xx]+1,xx,1);
    				if(tong.find(yy)!=tong.end())work(yy-tong[yy]+1,yy,-1);
    			}
    			else{
    				int xx=ls,yy=rs+1;
    				if(tong.find(xx)!=tong.end())work(xx-tong[xx]+1,xx,1);
    				if(tong.find(yy)!=tong.end())work(yy-tong[yy]+1,yy,-1);
    			}
    		}
    		else{
    			x+=tag;
    			if(a[p]>=ls&&a[p]<=rs)work(a[p]-tong[a[p]]+1,a[p]-tong[a[p]]+1,-1);
    			tong[a[p]]--;
    			a[p]=x;
    			tong[a[p]]++;
    			if(a[p]>=ls&&a[p]<=rs)work(a[p]-tong[a[p]]+1,a[p]-tong[a[p]]+1,1);
    		}
    		P xx=query(1,1,maxn,ls-nowl,rs-nowl);
    		if(xx.first==0)printf("%d
    ",xx.second);
    		else puts("0");
    	}
    	return 0;
    }
    
  • 相关阅读:
    vertical-align:middle 垂直居中无效的原因
    meta标签的使用
    异常重试框架Spring Retry实践
    springboot 整合retry(重试机制)
    Centos7-Docker1.12开启守护进程(远程调用)
    Centos7安装docker与docker-compose
    Centos 下 Jenkins2.6 + Git + Maven Shell一件部署与备份
    Docker实战
    利用 Nginx 实现限流
    Feign拦截器应用 (F版)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10783134.html
Copyright © 2011-2022 走看看