zoukankan      html  css  js  c++  java
  • [bzoj 3110] [ZJOI2013] K大数查询

    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=3110

    题目:

    有N个位置,M个操作。操作有两种,每次操作如果是:

    • 1 a b c:表示在第a个位置到第b个位置,每个位置加上一个数c
    • 2 a b c:表示询问从第a个位置到第b个位置,第C大的数是多少。

    题解:

    注意每一个位置加上一个数并不是数字的加,而是在这个位置上多放一个数

    重新捡起OI的我现在还只会线段树套线段树的做法

    考虑权值线段树套区间线段树,对于每一段权值区间维护一棵区间线段树,线段树的每一个点代表在该区间内当前权值所有的元素出现的次数

    输出答案的时候二分查找

    蛮好维护的不是吗?注意要动态开点,顺便把加入的数给离散化一下

    代码:

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    
    const int N=5e4+15;
    int n,m,tot,cnt;
    int root[N<<2];
    ll a[N];
    struct E
    {
        int op,a,b;
        ll c;
    }e[N];
    struct Tree
    {
        int l,r,lazy;ll s;
    }t[N*400];
    inline ll read()
    {
        char ch=getchar();ll s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    void pushdown(int o,int l,int r)
    {
        if (!t[o].lazy||l==r) return;
        int mid=l+r>>1;
        int d=t[o].lazy;t[o].lazy=0;
        if (!t[o].l) t[o].l=++cnt;
        if (!t[o].r) t[o].r=++cnt;
        t[t[o].l].lazy+=d;
        t[t[o].l].s+=(mid-l+1)*d;
        t[t[o].r].lazy+=d;
        t[t[o].r].s+=(r-mid)*d;
    }
    void pushup(int o)
    {
        t[o].s=t[t[o].l].s+t[t[o].r].s;
    }
    void ins2(int &o,int l,int r,int x,int y)
    {
        if (!o) o=++cnt;
        if (l>=x&&r<=y)
        {
            t[o].s+=r-l+1;
            t[o].lazy++;
            return;
        }
        pushdown(o,l,r);
        int mid=l+r>>1;
        if (x<=mid) ins2(t[o].l,l,mid,x,y);
        if (y>mid) ins2(t[o].r,mid+1,r,x,y);
        pushup(o);
    }
    void ins1(int o,int l,int r,int x,int y,int z)//对每一个包含添加的数的区间在x~y的值都加1 
    {
        ins2(root[o],1,n,x,y);
        if (l==r) return;
        int mid=l+r>>1;
        if (z<=mid) ins1(o<<1,l,mid,x,y,z);
        else ins1(o<<1|1,mid+1,r,x,y,z);
    }
    ll qsum(int o,int l,int r,int x,int y)
    {
        if (!o) return 0;
        if (l>=x&&r<=y) return t[o].s;
        pushdown(o,l,r);
        int mid=l+r>>1;ll re=0;
        if (x<=mid) re+=qsum(t[o].l,l,mid,x,y);
        if (y>mid) re+=qsum(t[o].r,mid+1,r,x,y);
        return re;
    }
    int query(int o,int l,int r,int a,int b,int c)
    {
        if (l==r) return l;
        int mid=l+r>>1;
        ll sz=qsum(root[o<<1|1],1,n,a,b);
        if (sz>=c) return query(o<<1|1,mid+1,r,a,b,c);
        else return query(o<<1,l,mid,a,b,c-sz);
    }
    int main()
    {
        n=read();m=read();
        for (int i=1;i<=m;i++)
        {
            e[i].op=read();
            e[i].a=read();e[i].b=read();e[i].c=read();
            if (e[i].op==1) a[++tot]=e[i].c;
        }
        sort(a+1,a+1+tot);
        tot=unique(a+1,a+1+tot)-a-1;
        for (int i=1;i<=m;i++) if (e[i].op==1) e[i].c=lower_bound(a+1,a+1+tot,e[i].c)-a;
        for (int i=1;i<=m;i++)
        {
            if (e[i].op==1) ins1(1,1,tot,e[i].a,e[i].b,e[i].c);
            if (e[i].op==2) printf("%lld
    ",a[query(1,1,tot,e[i].a,e[i].b,e[i].c)]);
        }
        return 0;
    } 
  • 相关阅读:
    NOI2010 能量采集
    NOI2011 兔兔与蛋蛋游戏
    动态规划——min/max的单调性优化总结
    NOI2011 NOI嘉年华
    NOI2011 阿狸的打字机
    NOI2011 智能车比赛
    NOI2011 兔农
    NOI2012 魔幻棋盘
    NOI2012 美食节
    NOI2012 迷失游乐园
  • 原文地址:https://www.cnblogs.com/xxzh/p/10581081.html
Copyright © 2011-2022 走看看