1 条题解

  • 0
    @ 2025-8-24 21:54:37

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 小粉兔
    Always continue; Never break;

    搬运于2025-08-24 21:54:37,当前版本为作者最后更新于2018-01-06 16:04:46,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    我是洛谷全站跑得最快的,1488ms。 使用筛选最优解的新功能就可以找到我。 使用的是 NOIP 范围的算法,不是平衡树,是树状数组。


    考虑前 50%50 \%

    观察到 q500q \leq 500,也就是说有效的行数不超过 500500 行。

    我们把行数离散化。

    那么需要维护的数的数量最多只有 q(m1)+nq (m - 1) + n

    一次操作的复杂度最多是 n+m1n + m - 1

    那么时间复杂度 O(qlogq+q(n+m1))\mathcal O (q \log q + q (n + m - 1)),空间复杂度O(q(m1)+n)\mathcal O (q (m - 1) + n)


    再看接下来的 30%30 \%

    发现有 xi=1x_i = 1,也就是说,有效的格子只有第一行和最后一列。

    我们把第一行和最后一列压到一起去,那么我们要对这个序列支持:

    1. 删除第 kk 个元素

    2. 在末尾添加一个元素

    这个操作能用平衡树实现,但是我用树状数组来实现。

    用树状数组维护一个 01 序列,第 ii 位上是 0 表示这个位置上的数已经被删除了或者还没有被插入,第 ii 位上是 1 表示这一位上的数没有被删除。

    那么删除操作就是 101 \to 0,插入操作就是 010 \to 1

    kk 个元素就是前缀和为 kk 的位置。

    对于查找这个位置的操作,我使用树状数组二分,具体见代码,时间 O(logn)\mathcal O (\log n)


    那么最后的 20%20 \% 呢?

    定义一行中原来的元素为初始时这一行前 m1m - 1 个元素中,没有离队过的元素。

    我们观察到对于本来就在这一行中的元素,我们可以直接算出它的值,而不用存储。

    那么我们判断每一次询问是不是在本行的原来的元素中,如果是,直接判断掉。

    那么每一行的“非原来的元素”有多少个呢?

    我们不知道一行会有多少个,但是我们知道,所有行的这样的元素个数的总和不超过 qq 个。

    这启发了我们对于每一行,只对其“非原来的元素”开一个树状数组维护。

    而对于“原来的元素”,我们直接离线预处理。

    预处理时需要对所有的询问按照 xix_i 为第一关键字,询问编号为第二关键字排序。

    再对最后一列单独处理。

    时间复杂度 O(qlogq+qlogm+qlog(n+q))\mathcal O (q \log q + q \log m + q \log (n + q)),空间复杂度 O(n+m+q)O(n + m + q)

    具体看代码吧!

    代码:

    #pragma GCC optimize("O2")
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define dF(i,a,b) for(int i=a;i>=b;--i)
    #define F2(i,a,b) for(int i=a;i<b;++i)
    #define getchar() (SS==TT&&(TT=(SS=BB)+fread(BB,1,1<<15,stdin),TT==SS)?EOF:*SS++)
    #define RR register
    char BB[1<<15],*SS=BB,*TT=BB;
    inline int read(){
    	RR int x;RR bool f;RR char c;
    	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
    	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
    	return f?-x:x;
    }
    using namespace std;
    int q,I[300010];
    long long n,m,a[300010],b[300010];
    inline bool cmp(int p1,int p2){return a[p1]==a[p2]?p1<p2:a[p1]<a[p2];}
    int h[300010],len[300010],len2[300010],bit[900010];
    long long arr[900010];
    long long Ans[300010];
    inline void Ins(int*array,int siz,int i,int x){for(;i<=siz;array[i]+=x,i+=i&-i);}
    inline int binary(int*array,int siz,int x){
    	int l=1,r,mid,sum,ans;
    	while(l<=siz&&array[l]<x) l<<=1, ans=l;
    	r=l; sum=array[l>>=1];
    	while(l<r-1){
    		mid=l+r>>1;
    		if(mid>siz||array[mid]+sum>=x) r=mid, ans=mid;
    		else l=mid, sum+=array[l];
    	} ans=r;
    	return ans;
    }
    int stk[300001],top;
    int main(){
    	n=read(), m=read(), q=read();
    	F(i,1,q) a[i]=read(), b[i]=read(), I[i]=i;
    	sort(I+1,I+q+1,cmp);
    	F(i,1,m-1) Ins(bit,m-1,i,1);
    	F(i,1,n) len[i]=m-1;
    	F(i,1,q){
    		if(a[I[i-1]]!=a[I[i]])
    			while(top) Ins(bit,m-1,stk[top--],1);
    		if(b[I[i]]>len[a[I[i]]]) continue;
    		int pos=binary(bit,m-1,b[I[i]]);
    		Ans[I[i]]=(a[I[i]]-1)*m+pos;
    		Ins(bit,m-1,pos,-1);
    		stk[++top]=pos;
    		--len[a[I[i]]];
    	}
    	int iter=0;
    	F(i,1,n){
    		while(iter<=q&&a[I[iter]]<i) ++iter;
    		h[i]=iter-1;
    	}
    	h[n+1]=q;
    	memset(bit,0,sizeof bit);
    	F(i,1,n) len[i]=0, len2[i]=m-1; len[n+1]=n;
    	F(i,1,n) Ins(bit+h[n+1],n+q,i,1), arr[q+i]=i*m;
    	F(i,1,q){
    		if(Ans[i]){
    			int pos=binary(bit+h[n+1],n+q,a[i]);
    			Ins(bit+h[n+1],n+q,pos,-1);
    			Ins(bit+h[n+1],n+q,++len[n+1],1);
    			arr[h[n+1]+len[n+1]]=Ans[i];
    			Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],++len[a[i]],1);
    			arr[h[a[i]]+len[a[i]]]=arr[h[n+1]+pos];
    			--len2[a[i]];
    		}
    		else{
    			int pos=binary(bit+h[n+1],n+q,a[i]);
    			Ins(bit+h[n+1],n+q,pos,-1);
    			Ins(bit+h[n+1],n+q,++len[n+1],1);
    			if(b[i]!=m){
    				int pos2=binary(bit+h[a[i]],h[a[i]+1]-h[a[i]],b[i]-len2[a[i]]);
    				Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],pos2,-1);
    				Ans[i]=arr[h[a[i]]+pos2];
    				Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],++len[a[i]],1);
    				arr[h[a[i]]+len[a[i]]]=arr[h[n+1]+pos];
    			} else Ans[i]=arr[h[n+1]+pos];
    			arr[h[n+1]+len[n+1]]=Ans[i];
    		}
    	}
    	F(i,1,q) printf("%lld\n",Ans[i]);
    	return 0;
    }
    
    • 1

    信息

    ID
    2220
    时间
    2000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者