• 带插入区间K小值


    新写一篇题解,彻底了结这道毒瘤卡常题

    从我的上一篇带插入区间K小值题解最后得到了一个时间复杂度为 (O(n imes sqrt {n log {n}} imes log {n}))的解法,凭借优越的常数得到了60分的成绩,现在又有了一种更为优秀的做法。
    用块状链表可以实现单次插入 (O(sqrt {n}))的复杂度,假设没有了插入操作,就变成了这样一个题目:

    • 修改某一位置的值;
    • 询问区间第(k)小。

    这其实是lxl的Ynoi 2018 未来日记的弱化版。由于没有插入操作,所以可以将数列分成(sqrt {n}) 块,同时将权值分块,令(val[i][j]) 表示前(i)块权值在第(j)个值域的数的个数,(w[i][j])表示前(i)块权值为(j)的数的个数。修改暴力跑一遍前缀和即可,询问先早答案暴力从小到大枚举在哪一个值域里,然后在值域里暴力枚举答案即可。将分块写成块状链表,即可 (O(n sqrt {n}))的复杂度,适当卡常即可通过此题。

    代码:

    #include<bits/stdc++.h>
    #pragma GCC optimize(3)//找一个人少的时候用这个卡过去
    #define re register
    using namespace std;
    const int N=70000,M=275;
    struct BLO {
    	int lf,rf;
    	int sz,a[M*2+50],val[M+10],w[N+10];
    	//a[]:原数列  val[]:权值分块  w[]:权值 
    };BLO t[M+10]; int hed=0,tot=0;
    
    int n,m,ans=0,Val[M+10],W[N+10];
    char pr[1000010]; int top=0;
    
    inline int read() {
    	re int x=0;re char c=getchar();
    	while(c<'0'||c>'9')	c=getchar();
    	while(c>='0'&&c<='9')	x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x;
    }
    inline int Min(int x,int y) { return x<y?	x:y; }
    void print(int x) { if(x>9)	print(x/10); pr[top++]=x%10+'0'; }//输出优化
    void init() {
    	n=read(),hed=0,tot=n/M+1;
    	for(re int i=1,x;i<=n;++i) {
    		x=read(),t[i/M+1].a[++t[i/M+1].sz]=x;
    		++t[i/M+1].w[x],++t[i/M+1].val[x/M+1];
    	}
    	for(int i=0;i<tot;++i)	t[i].rf=i+1;
    	for(int i=1;i<=tot;++i)	t[i].lf=i-1;
    	for(int i=1;i<=tot;++i) {
    		for(int j=0;j<=N;j++) t[i].w[j]+=t[i-1].w[j];
    		for(int j=1;j<=M;j++)	t[i].val[j]+=t[i-1].val[j];
    	}
    	m=read();
    }
    void split(int u) {
    	++tot;
    	t[tot].lf=t[u].lf,t[t[u].lf].rf=tot,t[tot].rf=u,t[u].lf=tot;
    	for(re int i=0;i<=N;i++)	t[tot].w[i]=t[u].w[i];
    	for(re int i=1;i<=M;i++)	t[tot].val[i]=t[u].val[i];
    	for(re int i=1;i<=M;i++)	t[tot].a[i]=t[u].a[i];
    	for(re int i=M+1;i<=t[u].sz;++i)
    		t[u].a[i-M]=t[u].a[i],
    		--t[tot].val[t[u].a[i]/M+1],--t[tot].w[t[u].a[i]];
    	t[tot].sz=M,t[u].sz-=M;
    }
    void insert(int x,int k) {
    	int u=t[hed].rf; for(;x-1>t[u].sz;x-=t[u].sz,u=t[u].rf);
    	++t[u].sz;
    	for(re int i=t[u].sz;i>x;--i) t[u].a[i]=t[u].a[i-1];
    	t[u].a[x]=k; int tmp=u;
    	while(u)	++t[u].val[k/M+1],++t[u].w[k],u=t[u].rf;
    	if(t[tmp].sz==M*2)	split(tmp);
    }
    void modify(int x,int New) {
    	int u=t[hed].rf; for(;x>t[u].sz;x-=t[u].sz,u=t[u].rf);
    	int Old=t[u].a[x]; t[u].a[x]=New;
    	while(u)
    		--t[u].val[Old/M+1],--t[u].w[Old],
    		++t[u].val[New/M+1],++t[u].w[New],
    		u=t[u].rf;
    }
    void query(int x,int y,int k) {
    	int u=t[hed].rf,v=t[hed].rf; ans=0; bool flag=0;
    	for(;x>t[u].sz;x-=t[u].sz,u=t[u].rf);
    	for(;y>t[v].sz;y-=t[v].sz,v=t[v].rf);
    	for(re int i=1;i<x;++i)//边角块
    		--Val[t[u].a[i]/M+1],--W[t[u].a[i]];
    	for(re int i=1;i<=y;++i)
    		++Val[t[v].a[i]/M+1],++W[t[v].a[i]];
    	for(int i=1;;++i) {
    		if(Val[i]+t[t[v].lf].val[i]-t[t[u].lf].val[i]>=k) {
    			int mx=Min(i*M,N+1);
    			for(int j=(i-1)*M;j<mx;++j) {
    				if(W[j]+t[t[v].lf].w[j]-t[t[u].lf].w[j]>=k)
    					{ ans=j,flag=1;break; }
    				else
    					k-=(W[j]+t[t[v].lf].w[j]-t[t[u].lf].w[j]);
    			}
    			break;
    		}
    		k-=(Val[i]+t[t[v].lf].val[i]-t[t[u].lf].val[i]);
    	}
    	for(re int i=1;i<x;++i)//恢复(比memset快)
    		++Val[t[u].a[i]/M+1],++W[t[u].a[i]];
    	for(re int i=1;i<=y;++i)
    		--Val[t[v].a[i]/M+1],--W[t[v].a[i]];
    }
    void debug() {
    	for(int i=t[hed].rf;i;i=t[i].rf) {
    		printf(" ");
    		for(int j=1;j<=t[i].sz;j++)	printf("%d ",t[i].a[j]);
    	}
    	printf("
    ");
    }
    int main() {
    	#ifndef ONLINE_JUDGE
    	freopen("Dynamic Kth in range.in","r",stdin);
    	freopen("Dynamic Kth in range.out","w",stdout);
    	int cur=clock();
    	#endif
    	init(); int x,y,k; char opt;
    	for(;m;--m) {
    		opt=getchar();
    		while(opt<'A'||opt>'Z')	opt=getchar();
    		x=read()^ans,y=read()^ans;
    		switch(opt) {
    			case 'Q':
    				k=read()^ans,query(x,y,k);
    				print(ans),pr[top++]=10;
    				break;
    			case 'I':	insert(x,y);break;
    			default:	modify(x,y);break;
    		}
    		#ifndef ONLINE_JUDGE
    		ans=0;
    		#endif
    	}
    	pr[--top]='',puts(pr);
    	#ifndef ONLINE_JUDGE
    	printf(">>> %d ms.
    ",clock()-cur);
    	fclose(stdin),fclose(stdout);
    	#endif
    	return 0;
    }
    
  • 相关阅读:
    UVA 125 Numbering Paths
    UVA 515 King
    UVA 558 Wormholes
    UVA 10801 Lift Hopping
    UVA 10896 Sending Email
    SGU 488 Dales and Hills
    HDU 3397 Sequence operation
    数据库管理工具navicat的使用
    javascript封装animate动画
    关于webpack没有全局安装下的启动命令
  • 原文地址:https://www.cnblogs.com/daniel14311531/p/10182919.html
Copyright © 2020-2023  润新知