zoukankan      html  css  js  c++  java
  • LOJ数列分块入门1-9(3/9)

    数列分块入门1

    题目描述

    给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。

    第一行输入一个数字 n

    第二行输入 n 个数字,第 i个数字为 ai​​,以空格隔开。

    接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。

    若 opt=0,表示将位于 [l,r]的之间的数字都加 c

    若 opt=1,表示询问 ar的值(l 和 c 忽略)

    Solution:

    我们给每个块设置一个加法标记(就是记录这个块中元素一起加了多少),每次操作对每个整块直接O(1)标记,而不完整的块由于元素比较少,暴力修改元素的值。

    每次询问时返回元素的值加上其所在块的加法标记。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    const int MAXN = 50000 + 10;
    
    const int M = 225;
    
    inline int read()
    {
        char ch;
        int fl=1;
        int x=0;
        do{
          ch= getchar();
          if(ch=='-')
            fl=-1;
        }while(ch<'0'||ch>'9');
        do{
            x=(x<<3)+(x<<1)+ch-'0';
            ch=getchar();
        }while(ch>='0'&&ch<='9');
        return x*fl;
    }
    
    ll n;
    
    ll a[MAXN];
    
    ll opt,c,l,r;
    
    ll now,ks;
    
    ll add[M+10];
    
    int main()
    {
        n = read();
        ks=1;
        now=0;
        for(int i=1;i<=n;i++)
        {
            a[i] = read();
        }
        
        for(int i=1;i<=n;i++)
        {
            opt = read();l=read();r=read();c=read();
            if(opt==0)
            {
                if((l-1)/M+1!=(r-1)/M+1)
                {
                for(int j=l;j<=((l-1)/M+1)*M;j++) a[j]+=c;
                for(int j=(l-1)/M+2;j<=(r-1)/M;j++) add[j]+=c;
                for(int j=((r-1)/M)*M+1;j<=r;j++) a[j]+=c;
                }
                else
                {
                    for(int j=l;j<=r;j++) a[j]+=c;
                }
            
            }
            if(opt==1)
            {
                printf("%lld
    ",a[r]+add[(r-1)/M+1]);
            }
        }
    }

    数列分块入门2

    题目描述

    给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的元素个数。

    solution:

    考虑把原数列分成sqrt(n)块,每块维护一个有序的序列。

    首先考虑加法操作:对于整块的直接维护加法标记,不是整块的暴力修改元素,然后对块内元素重排。

    然后考虑查询:对于整块的由于块内元素有序,可以直接二分。对于不是整块的暴力统计。

    然而我以前写的代码WA了,加上最近没时间改,所以就不放代码了。

    数列分块入门3

    题目描述

    给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内比某个值x其小的最大元素。

    Solution:

    只有查询和2不一样,那改一下二分就行了QAQ

    数列分块入门4

    题目描述

    一个长为n的数列,以及n个操作,操作涉及区间加法,区间求和

    solution:

    分块后维护元素和,对于整块维护一个add标记

    数列分块入门9

    题目描述

    给出一个长为 n 的数列,以及 n 个操作,操作涉及区间众数。

    solution:

    不会,主席树暴力拿了一个LOJ rank1,又短又好写。(现在不是了)

    代码如下:

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    
    using namespace std;
    
    inline char nc()
    {
        static char buf[1000000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    
    inline int read()
    {
        char ch;
        int fl=1;
        int x=0;
        do{
          ch= nc();
          if(ch=='-')
            fl=-1;
        }while(ch<'0'||ch>'9');
        do{
            x=(x<<3)+(x<<1)+ch-'0';
            ch=nc();
        }while(ch>='0'&&ch<='9');
        return x*fl;
    }
    
    const int MAXN = 100000+10;
    
    struct p_tree
    {
        int sum;
        int lcc;
        int rcc;    
    } ;
    
    p_tree t[MAXN*25];
    
    int root[MAXN],cnt=0;
    
    struct node
    {
        int val;
        int id;
        friend bool operator < (node a1,node a2)
        {
            return a1.val<a2.val;    
        } 
    };
    
    node a[MAXN];
    
    int c[MAXN];
    
    int zsi,zsz;
    
    bool bz; 
    
    int ck;
    
    inline void update(int& rt,int x,int k,int l,int r)
    {
        t[++cnt]=t[rt];
        rt = cnt;
        t[rt].sum+=k;
        if(l==r) return;
        int mid=(l+r)>>1;
        if(x<=mid) update(t[rt].lcc,x,k,l,mid);
        else update(t[rt].rcc,x,k,mid+1,r);
    }
    
    inline void query(int l,int r,int x,int y)
    {
        if(bz) return;
        if(x==y)
        {
            if(zsz<t[r].sum-t[l].sum)
            {
                zsz=t[r].sum-t[l].sum;
                zsi=x;
            }
            if(zsz>(ck)/2) 
            {
                bz = true;
            }
            return;
        }
        else
        {
            if(zsz<t[t[r].lcc].sum-t[t[l].lcc].sum)
            {
                query(t[l].lcc,t[r].lcc,x,(x+y)>>1);    
            }
            if(zsz<t[t[r].rcc].sum-t[t[l].rcc].sum)
            {
                query(t[l].rcc,t[r].rcc,((x+y)>>1)+1,y);    
            } 
        } 
    }
    
    int n,q;
    
    int rankk[MAXN];
    
    int main()
    {
        n=read();
        for(register int i=1;i<=n;i++) a[i].val=read(),a[i].id=i;;
        root[0]=0;
        t[0].sum=t[0].lcc=t[0].rcc=0;
        sort(a+1,a+n+1);
        int top=0;
        for(register int i=1;i<=n;i++)
        {
            if(a[i].val!=a[i-1].val) top++;
            c[a[i].id]=top;
            rankk[top]=a[i].val;
        }
        for(register int i=1;i<=n;i++)
        {
            root[i]=root[i-1];
            update(root[i],c[i],1,1,100000);
        }
        zsi=0,zsz=0;
        for(register int i=1;i<=n;i++)
        {
            bz = false;
            int u=read(),v=read();
     
            if(u>v) swap(u,v);
            ck = v-u+1;
            zsi = 0,zsz = 0;
            query(root[u-1],root[v],1,100000);
            printf("%d
    ",rankk[zsi]);
        }
    } 

    我暴力似乎碾标算了。。。291ms

    后面的留坑

  • 相关阅读:
    C++中的名字重整技术
    Linux下C++开发常用命令
    《Effective C++(第三版)》 的55条建议
    我也介绍下sizeof与strlen的区别
    POJ
    HDU
    HDU-1754-I Hate It(单点更新+区间查询)
    HDU多校1003-Divide the Stones(构造)
    Just an Old Puzzle(2019多校1007)
    Idiomatic Phrases Game(最短路+注意坑点)
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/8982715.html
Copyright © 2011-2022 走看看