zoukankan      html  css  js  c++  java
  • 【洛谷P3332】K大数查询

    题目

    题目链接:https://www.luogu.com.cn/problem/P3332
    你需要维护 (n) 个可重整数集,集合的编号从 (1)(n)
    这些集合初始都是空集,有 (m) 个操作:

    • 1 l r c:表示将 (c) 加入到编号在 ([l,r]) 内的集合中
    • 2 l r c:表示查询编号在 ([l,r]) 内的集合的并集中,第 (c) 大的数是多少。

    注意可重集的并是不去除重复元素的,如 ({1,1,4}cup{5,1,4}={1,1,4,5,1,4})

    思路

    整体二分板子题。
    我们将操作整体二分,假设答案在 ([l,r]) 的询问操作和能对 ([l,r]) 有贡献的修改操作所在集合为 ([ql,qr]),那么我们依次枚举操作。如果该操作是询问操作,那么就在线段树上查询询问区间的和是否不小于 (c)。如果是,说明答案应该更大,否则应该更小。对于修改操作,如果修改的值不小于 (mid),那么我们就将它所对应区间全部加上 (1) 的贡献,然后将它放到 ([mid,r]) 区间内,否则不计入贡献并放进 ([l,mid)) 内。
    时间复杂度 (O((n+m)log n))

    代码

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    typedef long long ll;
    
    const int N=50010;
    int n,m,Q,ans[N];
    
    struct Query
    {
    	int opt,l,r,id;
    	ll c;
    }ask[N],cpy[N];
    
    struct SegTree
    {
    	ll cnt[N*8],lazy[N*8];
    	
    	void pushdown(int x,int l,int r)
    	{
    		if (lazy[x])
    		{
    			int mid=(l+r)>>1;
    			cnt[x*2]+=1LL*(mid-l+1)*lazy[x];
    			cnt[x*2+1]+=1LL*(r-mid)*lazy[x];
    			lazy[x*2]+=lazy[x];
    			lazy[x*2+1]+=lazy[x];
    			lazy[x]=0;
    		}
    	}
    	
    	void pushup(int x)
    	{
    		cnt[x]=cnt[x*2]+cnt[x*2+1];
    	}
    	
    	void update(int x,int l,int r,int ql,int qr,ll val)
    	{
    		if (ql<=l && r<=qr)
    		{
    			cnt[x]+=(r-l+1)*val; lazy[x]+=val;
    			return;
    		}
    		pushdown(x,l,r);
    		int mid=(l+r)>>1;
    		if (ql<=mid) update(x*2,l,mid,ql,qr,val);
    		if (qr>mid) update(x*2+1,mid+1,r,ql,qr,val);
    		pushup(x);
    	}
    	
    	ll query(int x,int l,int r,int ql,int qr)
    	{
    		if (ql<=l && r<=qr) return cnt[x];
    		pushdown(x,l,r);
    		int mid=(l+r)>>1,sum=0;
    		if (ql<=mid) sum+=query(x*2,l,mid,ql,qr);
    		if (qr>mid) sum+=query(x*2+1,mid+1,r,ql,qr);
    		return sum;
    	}
    }seg;
    
    void binary(int l,int r,int ql,int qr)
    {
    	if (l==r)
    	{
    		for (int i=ql;i<=qr;i++)
    			if (ask[i].opt==2) ans[ask[i].id]=l;
    		return;
    	}
    	int mid=(l+r+1)>>1,p=ql-1,q=qr+1;
    	for (int i=ql;i<=qr;i++)
    		if (ask[i].opt==1)
    		{
    			if (ask[i].c>=mid)
    			{
    				seg.update(1,1,n*2+1,ask[i].l,ask[i].r,1);
    				cpy[--q]=ask[i];
    			}
    			else cpy[++p]=ask[i];
    		}
    		else
    		{
    			int cnt=seg.query(1,1,n*2+1,ask[i].l,ask[i].r);
    			if (1LL*cnt<ask[i].c) 
    			{
    				ask[i].c-=cnt; 
    				cpy[++p]=ask[i];
    			}
    			else cpy[--q]=ask[i];
    		}
    	for (int i=ql;i<=p;i++) ask[i]=cpy[i];
    	for (int i=qr;i>=q;i--) ask[i]=cpy[qr-i+q];
    	for (int i=ql;i<=qr;i++)
    		if (ask[i].opt==1 && ask[i].c>=mid)
    			seg.update(1,1,n*2+1,ask[i].l,ask[i].r,-1);
    	binary(l,mid-1,ql,p);
    	binary(mid,r,q,qr);
    }
    
    signed main()
    {
    	scanf("%lld%lld",&n,&m);
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%lld%lld%lld",&ask[i].opt,&ask[i].l,&ask[i].r);
    		scanf("%lld",&ask[i].c);
    		if (ask[i].opt==1) ask[i].c+=n+1;
    			else ask[i].id=++Q;
    	}
    	binary(1,2*n+1,1,m);
    	for (int i=1;i<=Q;i++)
    		printf("%lld
    ",ans[i]-n-1);
    	return 0;
    }
    
  • 相关阅读:
    Tiny_4412的NFS挂载
    tiny4412学习一:编译uboot,体验裸机
    开通博客,记录历程,开启新的征程
    mysql 多表联合做运算(求俩点的距离)
    golang gin框架使用图形验证码
    js rgb和16进制相互转换
    [转载] Centos7的安装、Docker1.12.3的安装,以及Docker Swarm集群的简单实例
    openstack golang sdk使用
    sendcloud golang 发送短信 示例代码
    Harbor配置https,并安装内容信任插件(notary)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14232374.html
Copyright © 2011-2022 走看看