zoukankan      html  css  js  c++  java
  • [loj6278]数列分块入门2

    做法1

    以$K$为块大小分块,并对每一个块再维护一个排序后的结果,预处理复杂度为$o(nlog K )$

    区间修改时将整块打上标记,散块暴力修改并归并排序,单次复杂度为$o(frac{n}{K}+K)$

    区间查询时在整块中二分,散块暴力枚举,单次复杂度为$o(frac{n}{K}log K+K)$

    显然取块大小为$K=sqrt{nlog n}$时最优,单次复杂度均为$o(nsqrt{nlog n})$

    时间复杂度为$o(nlog n)-o(sqrt{nlog n})$

    做法2

    瓶颈显然在于整块的二分,考虑对其批量处理

    具体的,对于整块的询问先记录在该块上而不执行,在当一个块要被作为散块暴力修改时再处理之前记录的所有操作(标记可以先减去,注意到该块的序列在这次修改前不会变化)

    将这些询问基数排序(当底数较大时可以认为是线性的),再利用单调性进行查询,即做到了这样的查询均摊线性(注意$o(K)$的复杂度暴力修改本来就有),那么取$K=sqrt{n}$即可

    时间复杂度为$o(nlog n)-o(sqrt{n})$

    做法3

    实际上是在$frac{n}{K}$个长为$K$的序列中二分,那么即可使用类似[luogu6466]分散层叠算法的做法

    具体的,再选择一个阈值$B$,并将连续$B$个块称为一组,对每一组仅考虑每一个块中(排序后)下标是$B$的倍数的位置,即构成$B$个长度为$frac{K}{B}$的序列,对其使用做法4维护

    预处理的复杂度即为$o(frac{n}{BK}cdot K)=o(frac{n}{B})$(当然还有$o(nlog n)$的排序复杂度)

    区间修改时将整组和整块打上标记,散组和散块都暴力修改,单次复杂度为$o(frac{n}{K}+K)$

    区间查询时,将位置分为以下三类:

    1.对整组直接查询,至多$o(frac{n}{BK})$组,每组的复杂度为$o(Blog B+log BK)$(可以$o(B+log BK)$找到每一个块中第一个下标是$B$的倍数且大于等于$x^{2}$的数,再向前$B$个位置二分即可)

    2.对散组的整块二分查询,至多$o(B)$个块,每块的复杂度为$o(log K)$

    3.对散组的散块暴力查询,至多$o(K)$个位置,复杂度也为$o(K)$

    综上,单次复杂度为$o(K+frac{n}{K}log B+frac{n}{BK}log BK)$,显然取$K=sqrt{nlog log n},B=log n$最优

    时间复杂度为$o(nlog n)-o(sqrt{nloglog n})$

    做法4

    同样使用[luogu6466]分散层叠算法的做法,但考虑做法4沿用做法3的部分

    具体的,直接对$frac{n}{K}$个块建立一个分治结构(也即线段树),并且以$frac{1}{3}$的比例取元素(即合并时仅取下标是3的倍数的位置上的元素),此时序列长度和即为$o(n)$(当然取偶数位置也是$o(n)$的)

    区间修改时对整块打上标记(即线段树),并对散块暴力修改后重新维护,注意到一个叶子节点到根路径上的序列长度依次为$K,frac{2}{3}K,frac{4}{9}K,...$,那么总和即为$o(K)$,也即单次复杂度为$o(log frac{n}{K}+K)$

    区间查询时对整块直接在该结构上查询,只需要在根上二分一次并递归,注意到一共只有$o(frac{n}{K})$个节点,因此这部分的复杂度为$o(log K+frac{n}{K})$,散块暴力复杂度仍为$o(K)$

    综上,单次复杂度为$o(K+frac{n}{K})$,显然取$K=sqrt{n}$最优

    时间复杂度为$o(nlog n)-o(sqrt{n})$

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 50005
      4 #define K 300
      5 #define D 3
      6 #define ll long long
      7 #define L (k<<1)
      8 #define R (L+1)
      9 #define mid (l+r>>1)
     10 int n,k,p,l,r,x,ans,num[11],id[N],bl[N],st[K],ed[K],Pos[2],pos[K<<2][K][2];
     11 ll a[N],tag[K<<2],b[K<<2][K];
     12 int read(){
     13     int x=0,flag=0;
     14     char c=getchar();
     15     while ((c<'0')||(c>'9')){
     16         if (c=='-')flag=1;
     17         c=getchar();
     18     }
     19     while ((c>='0')&&(c<='9')){
     20         x=x*10+(c-'0');
     21         c=getchar();
     22     }
     23     if (flag)x=-x;
     24     return x;
     25 }
     26 void write(int x,char c=''){
     27     while (x){
     28         num[++num[0]]=x%10;
     29         x/=10;
     30     }
     31     if (!num[0])putchar('0');
     32     while (num[0])putchar(num[num[0]--]+'0');
     33     putchar(c);
     34 }
     35 bool cmp(int x,int y){
     36     return a[x]<a[y];
     37 }
     38 void upd(int k,int l,int r,int x){
     39     vector<int>v0,v1;
     40     for(int i=l;i<=r;i++)a[i]+=x;
     41     for(int i=st[k];i<=ed[k];i++)
     42         if ((l<=id[i])&&(id[i]<=r))v0.push_back(id[i]);
     43         else v1.push_back(id[i]);
     44     for(int i=st[k],x=0,y=0;i<=ed[k];i++){
     45         if ((x<v0.size())&&((y==v1.size())||(cmp(v0[x],v1[y]))))id[i]=v0[x++];
     46         else id[i]=v1[y++];
     47     }
     48 }
     49 void get(int k,int x){
     50     b[k][0]=0;
     51     for(int i=st[x];i<=ed[x];i++)b[k][++b[k][0]]=a[id[i]];
     52 }
     53 void up(int k){
     54     b[k][0]=0;
     55     int x=1,y=1;
     56     while ((x<=b[L][0])||(y<=b[R][0])){
     57         if ((x<=b[L][0])&&((y>b[R][0])||(b[L][x]+tag[L]<b[R][y]+tag[R]))){
     58             b[k][++b[k][0]]=b[L][x]+tag[L];
     59             pos[k][b[k][0]][0]=x;
     60             pos[k][b[k][0]][1]=0;
     61             x+=D;
     62         }
     63         else{
     64             b[k][++b[k][0]]=b[R][y]+tag[R];
     65             pos[k][b[k][0]][0]=0;
     66             pos[k][b[k][0]][1]=y;
     67             y+=D;
     68         }
     69     }
     70     memset(Pos,0,sizeof(Pos));
     71     for(int i=1;i<=b[k][0];i++)
     72         for(int p=0;p<2;p++){
     73             if (pos[k][i][p])Pos[p]=pos[k][i][p];
     74             pos[k][i][p]=Pos[p];
     75         }
     76 }
     77 void build(int k,int l,int r){
     78     if (l==r){
     79         get(k,l);
     80         return;
     81     }
     82     build(L,l,mid);
     83     build(R,mid+1,r);
     84     up(k);
     85 }
     86 void update_point(int k,int l,int r,int x){
     87     if (l==r){
     88         get(k,x);
     89         return;
     90     }
     91     if (x<=mid)update_point(L,l,mid,x);
     92     else update_point(R,mid+1,r,x);
     93     up(k);
     94 }
     95 void update_seg(int k,int l,int r,int x,int y,int z){
     96     if ((l>y)||(x>r))return;
     97     if ((x<=l)&&(r<=y)){
     98         tag[k]+=z;
     99         return;
    100     }
    101     update_seg(L,l,mid,x,y,z);
    102     update_seg(R,mid+1,r,x,y,z);
    103     up(k);
    104 }
    105 ll query_tag(int k,int l,int r,int x){
    106     if (l==r)return tag[k];
    107     if (x<=mid)return query_tag(L,l,mid,x)+tag[k];
    108     return query_tag(R,mid+1,r,x)+tag[k];
    109 }
    110 int query_seg(int k,int l,int r,int x,int y,int z,ll w){
    111     if ((l>y)||(x>r)||(!z))return 0;
    112     if (l==r)return z;
    113     int zl=pos[k][z][0],zr=pos[k][z][1];
    114     while ((zl<b[L][0])&&(b[L][zl+1]+tag[L]<w))zl++;
    115     while ((zr<b[R][0])&&(b[R][zr+1]+tag[R]<w))zr++;
    116     return query_seg(L,l,mid,x,y,zl,w-tag[L])+query_seg(R,mid+1,r,x,y,zr,w-tag[R]);
    117 }
    118 int query(int l,int r,ll x){
    119     int y=upper_bound(b[1]+1,b[1]+b[1][0]+1,x)-b[1]-1;
    120     return query_seg(1,1,bl[n],l,r,y,x);
    121 }
    122 int main(){
    123     n=read(),k=(int)sqrt(n);
    124     for(int i=1;i<=n;i++)a[i]=read();
    125     for(int i=1;i<=n;i++){
    126         id[i]=i;
    127         bl[i]=(i-1)/k+1;
    128         if (!st[bl[i]])st[bl[i]]=i;
    129         ed[bl[i]]=i;
    130     }
    131     for(int i=1;i<=bl[n];i++)sort(id+st[i],id+ed[i]+1,cmp);
    132     build(1,1,bl[n]);
    133     for(int i=1;i<=n;i++){
    134         p=read(),l=read(),r=read(),x=read();
    135         if (!p){
    136             if (bl[l]==bl[r]){
    137                 upd(bl[l],l,r,x);
    138                 update_point(1,1,bl[n],bl[l]);
    139             }
    140             else{
    141                 update_seg(1,1,bl[n],bl[l]+1,bl[r]-1,x);
    142                 upd(bl[l],l,ed[bl[l]],x);
    143                 update_point(1,1,bl[n],bl[l]);
    144                 upd(bl[r],st[bl[r]],r,x);
    145                 update_point(1,1,bl[n],bl[r]);
    146             }
    147         }
    148         else{
    149             ans=0;
    150             if (bl[l]==bl[r]){
    151                 ll z=(ll)x*x-query_tag(1,1,bl[n],bl[l]);
    152                 for(int j=l;j<=r;j++)
    153                     if (a[j]<z)ans++;
    154             }
    155             else{
    156                 ans=query(bl[l]+1,bl[r]-1,(ll)x*x);
    157                 ll z=(ll)x*x-query_tag(1,1,bl[n],bl[l]);
    158                 for(int j=l;j<=ed[bl[l]];j++)
    159                     if (a[j]<z)ans++;
    160                 z=(ll)x*x-query_tag(1,1,bl[n],bl[r]);
    161                 for(int j=st[bl[r]];j<=r;j++)
    162                     if (a[j]<z)ans++;
    163             }
    164             write(ans,'
    ');
    165         }
    166     }
    167     return 0;
    168 }
    View Code
  • 相关阅读:
    sqlserver中的锁与事务
    策略模式
    异步编程
    并行聚合操作
    EF中的自动追踪与代理
    C#6.0语法糖
    EF中使用SqlQuery进行参数化查询时抛出异常
    乐观并发
    为什么那么多公司不用 .NET
    sqlserver 更改跟踪相关知识
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15233495.html
Copyright © 2011-2022 走看看