• 数列分块入门 3


    给出一个长为n的数列,以及n个操作,操作涉及区间加法,
    询问区间内小于某个值x的前驱(比其小的最大元素)。
    Input
    第一行输入一个数字n。
    第二行输入n个数字,第ii个数字为a_i,以空格隔开。
    接下来输入n行询问,每行输入四个数字opt、l、r、c,以空格隔开。
    若opt=0,表示将位于[l,r]的之间的数字都加c。
    若opt=1,表示询问[l,r]中c的前驱的值(不存在则输出-1)。
    1<=n<=100000,−2^31<=others<=2^31
    Output
    对于每次询问,输出一行一个数字表示答案。
    Sample Input
    4
    1 2 2 3
    0 1 3 1
    1 1 4 4
    0 1 2 2
    1 1 2 4
    Sample Output
    3
    -1

    //利用set中的lowerbound进行查找第一个大于等于指定c的值 
    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    #include<set>
    #define N 100001
    using namespace std;
    set<int> tree[1100];
    int n,m,pos[N];
    int s[N],tag[N];
    void read(int &x)
    {
        char ch; bool ok;
        for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
        for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    void add(int l,int r,int c)
    {
        for(int i=l;i<=min(pos[l]*m,r);i++)
        {
            tree[pos[i]].erase(s[i]);
    		s[i]+=c;
            tree[pos[i]].insert(s[i]);
        }
        if(pos[l]!=pos[r])
        for(int i=(pos[r]-1)*m+1;i<=r;i++)
    	{
            tree[pos[i]].erase(s[i]);
    		s[i]+=c;
            tree[pos[i]].insert(s[i]);
        }
        for(int i=pos[l]+1;i<=pos[r]-1;i++)
    	    tag[i]+=c;
    }
    int findfront(int l,int r,int c)
    {
        int ans=-1,num;
        for(int i=l;i<=min(pos[l]*m,r);i++)//不成块的区间暴力操作 
        {
            num=tag[pos[i]]+s[i];
            if(num<c)
    		   ans=max(ans,num);//找出比c小的值 
        }
        if(pos[l]!=pos[r])
        for(int i=(pos[r]-1)*m+1;i<=r;i++)
        {
            num=tag[pos[i]]+s[i];
            if(num<c)
    		   ans=max(ans,num);//找出比c小的值 
        }
        for(int i=pos[l]+1;i<=pos[r]-1;i++)
        //成块的区间,其内部元素值并没有发生变化,只是加上了lazy标记 
        {
            int t=c-tag[i];
            set<int>::iterator k=tree[i].lower_bound(t);
            if(k==tree[i].begin())
    		    continue;
            k--;
            ans=max(ans,*k+tag[i]);
        }
        return ans;
    }
    int main()
    {
        read(n);m=sqrt(n);
        for(int i=1;i<=n;i++)
            pos[i]=(i-1)/m+1;  //数字i在哪一个块中 
        for(int i=1;i<=n;i++)
    	    read(s[i]),tree[pos[i]].insert(s[i]);
        for(int i=1;i<=n;i++)
        {
            int way,l,r,c;
            read(way),read(l),read(r),read(c);
            if(way==0) //[l,r]的之间的数字都加c
                add(l,r,c);
            if(way==1) //询问[l,r]中c的前驱的值
                printf("%d
    ",findfront(l,r,c));
        }
        return 0;
    }
    

      

  • 相关阅读:
    Oracle三大设计范式
    数据库查询4
    Oracle 常用内置函数
    数据库查询2
    数据库查询练习1
    Oracle 建表
    线程1—Runnable
    线程1—Thread
    输入输出2
    输入输出1
  • 原文地址:https://www.cnblogs.com/cutemush/p/12794553.html
Copyright © 2020-2023  润新知