• BZOJ3110:[Zjoi2013]K大数查询


    3110: [Zjoi2013]K大数查询

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 8652  Solved: 2608
    [Submit][Status][Discuss]

    Description

    有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
    如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

    Input

    第一行N,M
    接下来M行,每行形如1 a b c或2 a b c

    Output

    输出每个询问的结果

    Sample Input

    2 5
    1 1 2 1
    1 1 2 2
    2 1 1 2
    2 1 1 1
    2 1 2 3

    Sample Output

    1
    2
    1
    思路{  
     
    大意:N个位置,M个操作。操作有两种,每次操作如果是1
    a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2
    a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
    思路:可以树套树解决这个问题,也可以整体二分。
    何谓整体二分?就是对于多个询问操作,二分答案,但在二分答案的时候,传参当前答案的对于每组询问的可行范围。对当前若干个询问或者操作进行和二分的答案
    mid的比对,判断丢到左边一段的二分或者是右边一段的二分,得出每次二分答案的判定范围。然后递归求解(纯属个人理解)

    对于这道题:二分答案,如果当前插入操作的值大于mid应当记录这一个,可以线段树,也可以带区间修改的树状数组。把它加入哪一段呢?思考:若大于mid说明他能够影响更大的解,所以把它加入右端待询问的区间。(即递归下去为l=mid);反之小于mid加入左端待选区间(r=mid)。对于查询操作,由于加入顺序满足时间顺序,无需考虑冲突,所以查询待询问区间中大于mid的数有多少个。若大于了K,说明二分的答案mid小了。

        把它丢到右端待询问的区间.(即递归下去为l=mid)反之小于mid加入左端待选区间(r=mid *在这个地方需要记录一下贡献值!)然后清空本次树状数组或线段树。递归解两个子问题,知道二分答案的左

     右端点重合,就记录当前所有询问的答案即可。

    }
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #define inf (1<<30)
    #define il inline
    #define RG register
    #define LL long long
    #define N 500010
    using namespace std;
    struct ASK{int l,r,id,flag,k;}ask[N];
    int n,sum,m,ans[N];LL tree1[N],tree2[N];
    #define lowbit(o) o&(-o)
    void Insert(int x,int y){for(int i=x;i<=n;i+=lowbit(i))tree1[i]+=y,tree2[i]+=(LL)x*y;}
    LL query(int x){LL aa=0;for(int i=x;i;i-=lowbit(i))aa+=tree1[i]*(x+1)-tree2[i];return aa;}
    ASK quel[N],quer[N];
    il void solve(int head,int tail,int L,int R){
    	if(L==R){
    		for(RG int i=head;i<=tail;++i)ans[ask[i].id]=L;
    		return;
    	}int mid=(L+R+1)>>1;int ln=0,rn=0;bool ll=0,rr=0;
    	for(RG int i=head;i<=tail;++i){
    		if(ask[i].flag==1){
    			if(ask[i].k>=mid){
    				Insert(ask[i].l,1),Insert(ask[i].r+1,-1);
    				quer[++rn]=ask[i];
    			}
    			else quel[++ln]=ask[i];
    		}
    		else {
    			LL x=query(ask[i].r)-query(ask[i].l-1);
    			if(x>=ask[i].k)quer[++rn]=ask[i],rr=1;
    			else ll=1,ask[i].k-=x,quel[++ln]=ask[i];
    		}
    	}for(RG int i=head;i<=tail;++i)if(ask[i].flag==1&&ask[i].k>=mid)Insert(ask[i].l,-1),Insert(ask[i].r+1,1);  
    	for(RG int i=1;i<=ln;++i)ask[head+i-1]=quel[i];
    	for(RG int i=1;i<=rn;++i)ask[head+ln+i-1]=quer[i];
    	if(ll)solve(head,head+ln-1,L,mid-1);
    	if(rr)solve(head+ln,tail,mid,R);
    }
    il void work(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i){
    		scanf("%d%d%d%d",&ask[i].flag,&ask[i].l,&ask[i].r,&ask[i].k);
    		if(ask[i].flag==2)ask[i].id=++sum;
    	}
    	solve(1,m,1,n);
    	for(int i=1;i<=sum;++i)printf("%d
    ",ans[i]);
    }
    int main(){
        work();
        return 0;
    }
    
  • 相关阅读:
    美化滚动条
    js 格式转化
    vue 实现 前端生成随机验证码
    Vue.js CLI4 Vue.config.js标准配置
    在鼠标右键 新建 添加md文件
    节流和防抖
    关于IE 浏览器 GET 请求缓存问题
    VSCode 背景插件
    Java后台开发Tomcat添加https支持小程序开发过程
    InnoDB与MyISAM等存储引擎对比
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7157934.html
Copyright © 2020-2023  润新知