首页 > 其他分享 >#分块,二分#洛谷 5356 [Ynoi2017] 由乃打扑克

#分块,二分#洛谷 5356 [Ynoi2017] 由乃打扑克

时间:2024-02-26 16:11:40浏览次数:20  
标签:二分 5356 洛谷 10 int pos Ynoi2017 ans include

题目

支持区间加和区间查询第 \(k\) 小


分析

分块之后给每个整块排序,这样修改的时候整块打标记,散块直接分开把需要加的部分暴力加之后归并,就是 \(O(\sqrt{n})\) 的

查询的话,如果只有散块直接归并出结果,否则二分答案,加上小块合并成的整块,相当于是整体二分,就是 \(O(\sqrt{n}\log{a_i})\) 的

理论上块长取 \(\sqrt{n}\log{n}\) 实际上直接取根号更快


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100011;
int n,Q,a[N],lazy[N],b[N],rk[N],rK[N],Rk[N],L[N],R[N],pos[N],bl,_l[N],_r[N],_mid[N];
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
void print(int ans){
    if (ans<0) putchar('-'),ans=-ans;
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
bool cmp(int x,int y){return a[x]<a[y];}
void rebuild(int x,int l,int r,int z){
    Rk[0]=rK[0]=0;
    for (int i=L[x];i<=R[x];++i)
    if (l<=rk[i]&&rk[i]<=r) Rk[++Rk[0]]=rk[i],a[rk[i]]+=z;
        else rK[++rK[0]]=rk[i];
    int i1=1,j1=1,j=L[x];
    while (i1<=Rk[0]&&j1<=rK[0])
        if (a[Rk[i1]]<a[rK[j1]]) rk[j++]=Rk[i1++];
            else rk[j++]=rK[j1++];
    while (i1<=Rk[0]) rk[j++]=Rk[i1++];
    while (j1<=rK[0]) rk[j++]=rK[j1++];
}
int main(){
    n=iut(),Q=iut(),bl=sqrt(n);
    for (int i=1;i<=n;++i) a[i]=iut(),pos[i]=(i-1)/bl+1,rk[i]=i;
    for (int i=1;i<=n;++i) if (!L[pos[i]]) L[pos[i]]=i;
    for (int i=n;i>=1;--i) if (!R[pos[i]]) R[pos[i]]=i;
    for (int i=1;i<=pos[n];++i) sort(rk+L[i],rk+R[i]+1,cmp);
    for (int i=1;i<=Q;++i){
        int opt=iut(),l=iut(),r=iut(),z=iut();
        if (opt==1){
            if (r-l+1<z||z<=0){
                print(-1),putchar(10);
                continue;
            }
            int ans=-1;
            if (pos[l]==pos[r]){
                for (int j=L[pos[l]];j<=R[pos[r]]&&z;++j)
                    if (l<=rk[j]&&rk[j]<=r) ans=a[rk[j]]+lazy[pos[l]],--z;
                print(ans),putchar(10);
            }else{
                Rk[0]=rK[0]=0;
                for (int j=L[pos[l]];j<=R[pos[l]];++j)
                    if (rk[j]>=l) Rk[++Rk[0]]=a[rk[j]]+lazy[pos[l]];
                for (int j=L[pos[r]];j<=R[pos[r]];++j)
                    if (rk[j]<=r) rK[++rK[0]]=a[rk[j]]+lazy[pos[r]];
                int i1=1,j1=1,len=0;
                while (i1<=Rk[0]&&j1<=rK[0])
                if (Rk[i1]<rK[j1]) b[++len]=Rk[i1++];
                    else b[++len]=rK[j1++];
                while (i1<=Rk[0]) b[++len]=Rk[i1++];
                while (j1<=rK[0]) b[++len]=rK[j1++];
                if (pos[l]+1==pos[r]) print(b[z]),putchar(10);
                else{
                    int mn=b[1],mx=b[len],cnt=0;
                    for (int j=pos[l]+1;j<pos[r];++j){
                        mn=min(mn,a[rk[L[j]]]+lazy[j]);
                        mx=max(mx,a[rk[R[j]]]+lazy[j]);
                        _l[j]=L[j],_r[j]=R[j];
                    }
                    _l[0]=1,_r[0]=len;
                    while (mn<mx){
                        int mid=(0ll+mn+mx)>>1,_L,_R,CNT=cnt;
                        if (_l[0]<=_r[0]){
                            _L=_l[0]-1,_R=_r[0];
                            while (_L<_R){
                                int _MID=(_L+_R+1)>>1;
                                if (b[_MID]<=mid) _L=_MID;
                                    else _R=_MID-1;
                            }
                            _mid[0]=_L,cnt+=_L-_l[0]+1;
                        }
                        for (int j=pos[l]+1;j<pos[r];++j)
                        if (_l[j]<=_r[j]){
                            _L=_l[j]-1,_R=_r[j];
                            while (_L<_R){
                                int _MID=(_L+_R+1)>>1;
                                if (a[rk[_MID]]+lazy[j]<=mid) _L=_MID;
                                    else _R=_MID-1;
                            }
                            _mid[j]=_L,cnt+=_L-_l[j]+1;
                        }
                        if (cnt<z){
                            mn=mid+1;
                            if (_l[0]<=_r[0]) _l[0]=_mid[0]+1;
                            for (int j=pos[l]+1;j<pos[r];++j)
                                if (_l[j]<=_r[j]) _l[j]=_mid[j]+1;
                        }else{
                            mx=mid;
                            if (_l[0]<=_r[0]) _r[0]=_mid[0];
                            for (int j=pos[l]+1;j<pos[r];++j)
                                if (_l[j]<=_r[j]) _r[j]=_mid[j];
                            cnt=CNT;
                        }
                    }
                    print(mn),putchar(10);
                }
            }
        }else{
            if (pos[l]==pos[r]){
                if (L[pos[l]]==l&&R[pos[r]]==r) lazy[pos[l]]+=z;
                    else rebuild(pos[l],l,r,z);
            }
            else{
                if (l==L[pos[l]]) lazy[pos[l]]+=z;
                    else rebuild(pos[l],l,R[pos[l]],z);
                if (r==R[pos[r]]) lazy[pos[r]]+=z;
                    else rebuild(pos[r],L[pos[r]],r,z);
                for (int j=pos[l]+1;j<pos[r];++j) lazy[j]+=z;
            }
        }
    }
    return 0;
}

标签:二分,5356,洛谷,10,int,pos,Ynoi2017,ans,include
From: https://www.cnblogs.com/Spare-No-Effort/p/18034583

相关文章

  • 洛谷题单指南-贪心-P4995 跳跳!
    原题链接:https://www.luogu.com.cn/problem/P4995题意解读:消耗最大的体力跳完所有石头,贪心选择问题。解题思路:贪心策略:每次保证有最大的高度差即可,第一次跳到最大高度然后跳到最小高度,再跳到剩下的最大高度,再跳第二小高度,以此类推,直到跳完所有石头。100分代码:#include<bi......
  • 洛谷题单指南-贪心-P1094 [NOIP2007 普及组] 纪念品分组
    原题链接:https://www.luogu.com.cn/problem/P1094题意解读:贪心选择解题思路:贪心策略:将纪念品按价格由小到大排序,优先选择价格大的一直到超过分组价格上限,再选择价格小的直到超过价格上限,此为一组重复以上过程,直到所有数据都遍历到,采用一头一尾双指针即可。证明:如果最大价格......
  • 洛谷 P4198 楼房重建(线段树上二分)
    传送门解题思路动态维护区间里面单调递增斜率的长度需要维护两个信息:上述长度,和区间最大值(合并时需要)难点在于两个子区间的合并。左区间的楼房一定都能看见(没有遮挡),所以要在右区间二分,找到左面最大值lmax在右区间的位置,然后进行合并。复杂度两个log。AC代码#include<ios......
  • 洛谷题单指南-贪心-P1208 [USACO1.3] 混合牛奶 Mixing Milk
    原题链接:https://www.luogu.com.cn/problem/P1208题意解读:就是一个部分背包问题,贪心模版题。解题思路:优先选择单价低的牛奶即可。100分代码:#include<bits/stdc++.h>usingnamespacestd;constintN=5005;structfarmer{intprice,count;}f[N];boolcmp(fa......
  • 洛谷题单指南-贪心-P5019 [NOIP2018 提高组] 铺设道路
    原题链接:https://www.luogu.com.cn/problem/P5019题意解读:最短时间内填满道路,连在一起的不为0的坑可以一起填解题思路:方法1:分治法对于一段连续不同深度的坑,可以最多连续填的天数是最小深度在填满最小深度之后,分别针对其左边和右边的区域再进行填充,这就是此题分治法的理论基......
  • 洛谷【算法1-3】暴力枚举
    P2241统计方形(数据加强版)-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintINF=0x3f3f3f3f;lln,m,z,c;signedmain(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin......
  • 洛谷题单指南-贪心-P1478 陶陶摘苹果(升级版)
    原题链接:https://www.luogu.com.cn/problem/P1478题意解读:题目的本质是任务安排问题,有n件任务,每件任务耗时不同,在一定的时间内,如何安排任务使得完成的任务越多越好。解题思路:对于这类问题,贪心策略是优先完成容易的。回到摘苹果问题,要优先摘耗费力气小的,如果高度够不着,就跳过,......
  • 洛谷题单指南-贪心-P1106 删数问题
    原题链接:https://www.luogu.com.cn/problem/P1106题意解读:如何删数,让剩下的数最小,贪心选择问题。解题思路:先看样例:1754384第1次遍历:删掉7,剩下15438第2次遍历:删掉5,剩下1438第3次遍历:删掉4,剩下138第4次遍历:删掉8,剩下13,即为结果所以,贪心策略如下:1、遍历每一个数,如果前一......
  • 洛谷 P6785 [COCI2013-2014#6] KRUŽNICE
    COCI的题。显然,手模样例发现答案分为以下几个贡献:所有圆外面的那个大平面,贡献为\(1\)。每个圆至少被分成一部分,贡献为\(n\)。如果有一个圆被“拦腰截断了”,即整条直径上都被更小的圆填满了,就额外对答案贡献加\(1\),这也是我们所求部分。暴力跳set遇事不决,先打暴力;不加......
  • 洛谷题单指南-贪心-P3817 小A的糖果
    原题链接:https://www.luogu.com.cn/problem/P3817题意分析:吃最少的糖果,保证相邻糖果数之和不大于x,需要某种贪心策略。解题思路:依次遍历相邻两盒糖果如果糖果数之和大于x,必须要吃点一部分,使得糖果数之和刚好等于x贪心策略是:优先吃后一盒糖果,因为这样可以更利于后续的判断成立......