• BZOJ3110:[ZJOI2013]K大数查询


    浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3110

    外层一个权值线段树,内层一个位置线段树。对于外层权值线段树上的结点(p),它所属的内层线段树上记录每个点上有多少个值在外层的(l,r)内。

    对于加数,直接把外层线段树权值区间包涵要加的权值的所有点所属的内层线段树的区间(l,r)加一。

    对于查询,直接在外层线段树上二分查询即可。

    时间复杂度:(O(nlog^2n))

    空间复杂度:(O(nlog^2n))

    代码如下:

    #include <cstdio>
    using namespace std;
    typedef long long ll;
    
    const int maxn=5e4+5,maxsz=1.28e7;
    
    int n,m;
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    struct pos_segment_tree {
    	int tot;
    	ll sum[maxsz];
    	int ls[maxsz],rs[maxsz],tag[maxsz];
    
    	void add(int &p,int l,int r,int L,int R) {
    		if(!p)p=++tot;sum[p]+=R-L+1;
    		if(L<=l&&r<=R) {tag[p]++;return;}
    		int mid=(l+r)>>1;
    		if(R<=mid)add(ls[p],l,mid,L,R);
    		else if(L>mid)add(rs[p],mid+1,r,L,R);
    		else add(ls[p],l,mid,L,mid),add(rs[p],mid+1,r,mid+1,R);
    	}
    
    	ll query(int p,int l,int r,int L,int R) {
    		if(L<=l&&r<=R)return sum[p];
    		int mid=(l+r)>>1;ll res=1ll*tag[p]*(R-L+1);
    		if(R<=mid)res+=query(ls[p],l,mid,L,R);
    		else if(L>mid)res+=query(rs[p],mid+1,r,L,R);
    		else res+=query(ls[p],l,mid,L,mid)+query(rs[p],mid+1,r,mid+1,R);
    		return res;
    	}
    }T_inside;//标记永久化是为了卡常
    
    struct val_segment_tree {
    	int rt[maxn<<2];
    
    	void change(int p,int l,int r,int pos,int L,int R) {
    		while(1) {
    			T_inside.add(rt[p],1,n,L,R);
    			if(l==r)break;int mid=(l+r)>>1;
    			if(pos<=mid)p<<=1,r=mid;
    			else p=p<<1|1,l=mid+1;
    		}
    	}
    
    	int query(int p,int l,int r,int L,int R,int rk) {
    		while(l!=r) {
    			int mid=(l+r)>>1;
    			ll tmp=T_inside.query(rt[p<<1|1],1,n,L,R);
    			if(tmp>=rk)p=p<<1|1,l=mid+1;
    			else p=p<<1,r=mid,rk-=tmp;
    		}
    		return l;
    	}
    }T_out;//之所以这样写是为了卡常
    
    int main() {
    	n=read(),m=read();
    	for(int i=1;i<=m;i++) {
    		int opt=read(),l=read(),r=read(),k=read();
    		if(opt==1)T_out.change(1,1,n,k,l,r);
    		else printf("%d
    ",T_out.query(1,1,n,l,r,k));
    	}
    	return 0;
    }
    
  • 相关阅读:
    prometheus TSDB和外部存储系统
    Prometheus时序数据
    Prometheus简介
    Docker网络
    Ingress
    CRI和多容器运行时
    K8s容器存储接口(CSI)介绍
    EasyNVR视频广场点击视频后切换码流才能播放是什么原因?
    EasyNVR更新H265转H264模块内存增长且显示占用高如何解决?
    EasyNVR拉公网RTSP流失败问题调试和解决
  • 原文地址:https://www.cnblogs.com/AKMer/p/10167855.html
Copyright © 2020-2023  润新知