• LOJ2461. 「2018 集训队互测 Day 1」完美的队列


    (n)个队列,每个队列上限是(a_i)。如果队列超过上限就弹队头。

    每次给([l,r])的队列加入颜色(x)

    问所有时间中,存在于至少一个队列的颜色的个数。

    (nle 10^5)


    好题。

    离线。现在考虑求出一个操作的存活时间区间。

    分块,把操作拆成整块操作和散块操作,分别计算其存活时间并取max。

    显然,如果两种操作操作区间相同,那么前者比后者死得早。根据这个单调性搞搞事情:

    求整块操作的存活时间:

    如果固定一个整块操作,在刚操作时令(h_i=a_i);后面每次别的操作(整块或散块)操作能使得一些(h_i)减一。如果(max(h_i)le 0),则这个整块操作刚好死亡。

    根据单调性,在这个整块操作死去之后,计算下一个整块操作前先继承一些信息。显然要(h_i)加上两者间对队列(i)的操作次数。如果两者间存在散块操作,就可以扫整个块暴力更新,因为复杂度可以摊到其中任意一个散块上;如果不存在散块操作,就打个区间加一的标记。

    求散块操作的存活时间:

    对于散点分别维护个队列,队列中每个元素除了记操作编号之外,还有它被加入时整块操作加入过多少个。于是就可以得知两个散块操作之间,一共进行了多少次操作。最后用个双指针扫过去就可以得到每个散块操作的存活时间。

    时间(O(nsqrt n))

    并不是很好实现,整块和散块之间的各类影响错综复杂,写的时候要好好整理一下。

    精细实现2h左右,几乎没有调试,交上去没有WA,倒是一车的MLE。经过重重卡空间终于过去了……


    using namespace std;
    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    const int N=100005,B=400,INF=1000000000;
    int n,m;
    int a[N],c[N];
    struct Itv{int l,r;} p[N];
    int mx[N];
    vector<int> o[N];
    void upd(int t,int r){mx[t]=max(mx[t],r);}
    int buc[N];
    int bel[N],R[N],nb;
    struct info{int t,z;};
    int sz,firb,hp[B+5],cd;
    vector<info> qb;
    vector<int> qd[B+5];
    int zd[N];
    int h[B+5],mxh,tag;
    void reset_h(int lst){
    	mxh=-INF;
    	for (int i=1;i<=sz;++i){
    		while (hp[i]<qd[i].size() && zd[qd[i][hp[i]]]==lst)
    			hp[i]++,h[i]++;
    		mxh=max(mxh,h[i]+tag);
    	}
    }
    void adjust(int t){
    	if (firb<qb.size() && mxh<=0){
    		info f=qb[firb++];
    		upd(f.t,t);
    		if (firb<qb.size()){
    			info g=qb[firb];
    			if (g.z)
    				reset_h(firb);
    			mxh++,tag++;
    		}
    	}
    }
    void mdf_d(int st,int en,int t){
    	if (st>en) return;
    	cd++;
    	zd[t]=qb.size();
    	for (int i=st;i<=en;++i){
    		h[i]--;
    		qd[i].push_back(t);
    	}
    	mxh=-INF;
    	for (int i=1;i<=sz;++i)
    		mxh=max(mxh,h[i]+tag);
    	adjust(t);
    }
    void mdf_b(int t,int os){
    	mxh--,tag--;
    	adjust(t);
    	if (firb==qb.size()){
    		mxh=-INF;
    		for (int i=1;i<=sz;++i){
    			mxh=max(mxh,h[i]=a[os+i]);
    			hp[i]=qd[i].size();
    		}
    		tag=0;
    	}
    	qb.push_back({t,cd});
    	cd=0;
    }
    void workd(int d,int ad){
    	for (int i=0,j=0;i<qd[d].size();++i){
    		while (j<qd[d].size() && (zd[qd[d][j]]+j)-(zd[qd[d][i]]+i)<=ad)
    			++j;
    		int tmp=(zd[qd[d][i]]+i+ad)-(zd[qd[d][j-1]]+j-1);
    		if (tmp==0)
    			upd(qd[d][i],qd[d][j-1]);
    		else{
    			tmp+=zd[qd[d][j-1]];
    			upd(qd[d][i],(tmp<=qb.size()?qb[tmp-1].t:m+1));
    		}
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&a[i]);
    	for (int i=1;i<=n;++i)
    		bel[i]=(i-1)/B+1,R[bel[i]]=i,nb=bel[i];
    	for (int i=1;i<=m;++i)
    		scanf("%d%d%d",&p[i].l,&p[i].r,&c[i]);
    	for (int i=1;i<=nb;++i){
    		sz=R[i]-R[i-1];
    		qb.clear();
    		for (int j=1;j<=sz;++j)
    			qd[j].clear(),h[j]=hp[j]=0;
    		firb=cd=mxh=tag=0;
    		for (int t=1;t<=m;++t)
    			if (p[t].l<=R[i-1]+1 && R[i]<=p[t].r)
    				mdf_b(t,R[i-1]);
    			else
    				mdf_d(max(p[t].l,R[i-1]+1)-R[i-1],min(p[t].r,R[i])-R[i-1],t);
    		for (;firb<qb.size();++firb)
    			upd(qb[firb].t,m+1);
    		for (int j=1;j<=sz;++j)
    			workd(j,a[j+R[i-1]]);
    	}
    	for (int i=1;i<=m;++i){
    		o[i].push_back(c[i]);
    		o[mx[i]].push_back(-c[i]);
    	}
    	int ans=0;
    	for (int i=1;i<=m;++i){
    		for (int j=0;j<o[i].size();++j){
    			int x=abs(o[i][j]),c=(o[i][j]>0?1:-1);
    			ans-=(buc[x]!=0);
    			buc[x]+=c;
    			ans+=(buc[x]!=0);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    React之Axios请求远程数据
    React生命周期改善组件性能
    React生命周期钩子/函数详细介绍
    React之ref操作DOM(ref = {input=>this.input = input})
    集成学习
    c++ primer plus 第五章 课后题答案
    c++ primer plus 第四章 课后题答案
    c++ primer plus 第三章 课后题答案
    c++ primer plus 第二章 课后题答案
    类别不平衡问题
  • 原文地址:https://www.cnblogs.com/jz-597/p/14999865.html
Copyright © 2020-2023  润新知