• ACM-T3分块


                                                     ty的难题

    题目背景

          国民男神ty又遇到了一个小难题,他在和xqj大神的争论中(谁更强),ty表示自己不会这个问题(装弱),于是他将这个问题交给了身为ty小迷弟(妹)的你。

    题目描述:给一个长为n的数列,以及n次操作。每次操作均有一串字符和3个数字组成(c,l,r,x);有两种操作:将区间l~r加上x,询问区间l,r中比x小的

    最大元素(若不存在则输出impossible),对应每个操作,字符分别为‘change’,‘query’。

    样例输入

    3

    1 2 3

    query 1 2 2

    change 1 2 1

    query 1 2 2

    样例输出

    1

    impossible

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    using namespace std;
    int blo,bl[100005],v[100005],n,lazy[1005];
    long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    set<int> st[1005];
    void clear(int x)
    {
        st[x].clear();
        for(int i=(x-1)*blo+1;i<=min(n,x*blo);i++)
        st[x].insert(v[i]);
        //sort(st[x].begin(),st[x].end());
    }
    void change(int l,int r,int val)
    {
        for(int i=l;i<=min(bl[l]*blo,r);i++)
        v[i]+=val;
        clear(bl[l]);
        if(bl[l]!=bl[r])
        {
            for(int i=r;i>=(bl[r]-1)*blo+1;i--)
            v[i]+=val;
            clear(bl[r]);
        }
        for(int i=bl[l]+1;i<=bl[r]-1;i++)
        lazy[i]+=val;
    }
    void query(int l,int r,int x)
    {
        int ans=-1;
        for(int i=l;i<=min(bl[l]*blo,r);i++)
        if(v[i]+lazy[bl[l]]<x)
        ans=max(ans,v[i]+lazy[bl[l]]);
        if(bl[l]!=bl[r])
        {
            for(int i=r;i>=(bl[r]-1)*blo+1;i--)
            if(v[i]+lazy[bl[r]]<x)
            ans-max(ans,v[i])+lazy[bl[r]];
        }
        for(int i=bl[l]+1;i<=bl[r]-1;i++)
        {
            int c=x-lazy[i];
            set<int>::iterator it1=st[i].lower_bound(c);
            if(st[i].begin()==it1) continue;
            it1--;
            ans=max(ans,*it1+lazy[i]);
        }
        if(ans==-1) printf("impossible
    ");else
        printf("%d
    ",ans);
    }
    int main()
    {    n=read();
        blo=sqrt(n);
        for(int i=1;i<=n;i++)
        v[i]=read(),bl[i]=(i-1)/blo+1,st[bl[i]].insert(v[i]);
        //for(int i=1;i<=bl[n];i++)
        //sort(st[i].begin(),st[i].end());
        char char_[10];
        for(int i=1;i<=n;i++)
        {
            scanf("%s",&char_);
            if(char_[0]=='c')
            {
                int l,r,val;
                scanf("%d %d %d",&l,&r,&val);
                change(l,r,val);
            }else{
                int l,r,x;
                scanf("%d %d %d",&l,&r,&x);
                query(l,r,x);
            }
        }
        return 0;
    }

     这个常数有点大,1100000的数据得3秒。

    每一次clear都更新整个块

    用set的性质可以直接改(删掉原来的,加上新的)

    但是这种写法貌似在这种题目里有问题(可能在一个块里前面有一个2,后面有一个2,现在将后面那个2改为3,在set中前面那个2会变成3),所以题解有问题!

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    using namespace std;
    int blo,bl[100005],v[100005],n,lazy[1005];
    long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    set<int> st[1005];    
    void change(int l,int r,int val)
    {
    for(int i=l;i<=min(bl[l]*blo,r);i++)
    {
    st[bl[l]].erase(v[i]);
    v[i]+=val;
    st[bl[r]].insert(v[i]);
    } 
    if(bl[l]!=bl[r])
    {
        for(int i=r;i>=(bl[r]-1)*blo+1;i--)
        {
            st[bl[r]].erase(v[i]);
            v[i]+=val;
            st[bl[r]].insert(v[i]);
        }
    }    
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
    lazy[i]+=val;
    }
    void query(int l,int r,int x)
    {
        int ans=-1;
        for(int i=l;i<=min(bl[l]*blo,r);i++)
        if(v[i]+lazy[bl[l]]<x)
            ans=max(ans,v[i]+lazy[bl[l]]);
        if(bl[l]!=bl[r])
        {    
            for(int i=r;i>=(bl[r]-1)*blo+1;i--)
            if(v[i]+lazy[bl[r]]<x)
            ans=max(ans,v[i])+lazy[bl[r]];
        }
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
    {
    int c=x-lazy[i];
    set<int>::iterator it1=st[i].lower_bound(c);
    if(st[i].begin()==it1) continue;
    it1--;
    ans=max(ans,*it1+lazy[i]);
    }
    if(ans==-1) printf("impossible
    ");else
    printf("%d
    ",ans);
    }
    int main()
    { n=read();
    blo=sqrt(n);
    for(int i=1;i<=n;i++)
    v[i]=read(),bl[i]=(i-1)/blo+1,st[bl[i]].insert(v[i]);
    //for(int i=1;i<=bl[n];i++)
    //sort(st[i].begin(),st[i].end());
    char char_[10];
    for(int i=1;i<=n;i++)
    {
    scanf("%s",&char_);
    if(char_[0]=='c')
    {
    int l,r,val;
    scanf("%d %d %d",&l,&r,&val);
    change(l,r,val);
    }else{
    int l,r,x;
    scanf("%d %d %d",&l,&r,&x);
    query(l,r,x);
    }
    }
    return 0;
    } 

     但是这样的话set的性质大部分已经不用,直接用vector常数更小

    #include<map>
    #include<set>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define mod 998244353
    #define pi acos(-1)
    #define inf 0x7fffffff
    #define ll long long
    using namespace std;
    ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,blo;
    int v[100005],bl[100005],atag[100005];
    set<int>st[105];
    void add(int a,int b,int c)
    {
        for(int i=a;i<=min(bl[a]*blo,b);i++)
        {
            v[i]+=c;
        }
        st[bl[a]].clear();
        for(int i=(bl[a]-1)*blo+1;i<=min(bl[a]*blo,n);i++)
        st[bl[a]].insert(v[i]);
        if(bl[a]!=bl[b])
        {
            for(int i=(bl[b]-1)*blo+1;i<=b;i++)
            {
                v[i]+=c;  
            }
            st[bl[b]].clear();
            for(int i=(bl[b]-1)*blo+1;i<=min(bl[b]*blo,n);i++)
            st[bl[b]].insert(v[i]);
        }
        for(int i=bl[a]+1;i<=bl[b]-1;i++)
            atag[i]+=c;
    }
    int query(int a,int b,int c)
    {
        int ans=-1;
        for(int i=a;i<=min(bl[a]*blo,b);i++)
        {
            int val=v[i]+atag[bl[a]];
            if(val<c)ans=max(val,ans);
        }
        if(bl[a]!=bl[b])        
            for(int i=(bl[b]-1)*blo+1;i<=b;i++)        
            {
                int val=v[i]+atag[bl[b]];
                if(val<c)ans=max(val,ans);
            }
        for(int i=bl[a]+1;i<=bl[b]-1;i++)
        {
            int x=c-atag[i];
            set<int>::iterator it=st[i].lower_bound(x);
            if(it==st[i].begin())continue;
            --it;
            ans=max(ans,*it+atag[i]);
        }
        return ans;
    }
    int main()
    {
        n=read();blo=1000;
        for(int i=1;i<=n;i++)v[i]=read();
        for(int i=1;i<=n;i++)
        {
            bl[i]=(i-1)/blo+1;
            st[bl[i]].insert(v[i]);
        }
        for(int i=1;i<=n;i++)
        {
            int f=read(),a=read(),b=read(),c=read();
            if(f==0)add(a,b,c);
            if(f==1)printf("%d
    ",query(a,b,c));
        }
        return 0;
    }
  • 相关阅读:
    虚拟化(五):vsphere高可用群集与容错(存储DRS是一种可用于将多个数据存储作为单个数据存储群集进行管理的功能)
    vmware 桌面虚拟化 horizon view 介绍(使用微软的RDP协议或vmware 专有的PCoIP协议,连接到虚拟桌面,并且可以使用本地的USB设备、本地存储)
    Delphi之萝莉调教篇
    编写自定义PE结构的程序(如何手写一个PE,高级编译器都是编译好的PE头部,例如MASM,TASM等,NASM,FASM是低级编译器.可以自定义结构)
    localStore的storage事件
    对称密码体制和非对称密码体制
    Span<T>和ValueTuple<T>性能是.Net Core非常关键的特性
    分布式高并发下Actor模型
    公众号及H5支付
    BIOS(Basic Input/Output System)是基本输入输出系统的简称
  • 原文地址:https://www.cnblogs.com/dancer16/p/6882025.html
Copyright © 2020-2023  润新知