優れたデータブロック構造の1-(v1.0を)

--- ---復元コンテンツ始まります

v1.0を、改正のギャングを求めます

我々はすべて知っているように、Xinlongの妹は悪性腫瘍です。

データ構造が多いがん。

これは、ブロックのうちで最もです。

優れた(暴力)ショー(力)のデータ構造を学ぶためまあ、彼らは巣今日 - ブロック

ラブリー吉野。

QAQ

 

パート1ブロックとは何ですか?

各ブロックの複数のブロックに配列に等しい定義、、、保守情報、および組み合わせによってブロック、。

パート2ブロック原則、達成するために?

今、私たちは間隔を求めていると、シーケンス番号、区間追加ごとに、問題を抱えている(私たちがいないと仮定すると、ツリーラインと呼ばれるものです)

暴力の実践:

暴力、暴力の問い合わせを修正し、明らかにT、O(n²)の時間計算量を飛びます。

暴力を最適化する検討します。

Ωブロックにシーケンスは、各ブロックはTAGを維持します。

L、R-片部との間隔が断片化ブロックの部分に分割されています。

モノリシック部分については、我々は、タグブロックxに直接追加します。

散乱部分については、我々は暴力を追加します。

クエリは同じです。

ブロックの部分のために、ブロックは、元と+(N /ω)*タグです>

散乱部品、直接暴力お問い合わせください。

時間の複雑さ。

作品なので、O(ω)の時間複雑ωアップ。

(N /ω)の時間複雑度はO(n /ω)までによって断片化。

明らかω= SQRT(n)が最適です。

したがって、ブロックのM *のSQRT(N)の時間複雑。

ブロックは、おそらく実現します:

ブロックに属する点を表すベルレコードアレイ。

LFT、RGTアレイを記録する、各ブロックの代表点は、左と右の点

そして、情報と統計の各部分。

各クエリのために

同じブロック、暴力の照会で2つのエンドポイントの場合。

それ以外の場合は、情報のクエリの最初の部分は、散乱暴力問合せ部

各変更のため。

情報タグの直接のヒットシングル曲は、暴力断片化されたパーツを変更します。

たとえば、三の部分は、(原因異なる時間にタイトルが全く異なる、コードスタイルかもしれ書い変更になる場合があります)

1. Danfeiヒツジ(luogu3203)

タイトル効果:Lostmonkey羊は、i番目のユニットに到達したとき、それは、次のステップKIを再生KI + I番目のデバイスに到達し、各デバイスが初期弾性係数kiを設定し、n個のデバイスのラインに沿って地面に置きます、iは装置、羊DanfeiのKIの存在を+た場合。羊は、いくつかのシェルがDanfeiます後、それは、i番目のユニットから開始されたときに知ってほしいです。

遮断手段の基本的な問題は、記録時間のそれぞれは、現在のポイント位置のブロックから飛び出すノードの少数後にジャンプすることができます。

代码:

#include <iostream>
#include <stdio.h> #include <string> #include <math.h> using namespace std; const int maxn=200005,maxm=505; int n,m,Q,num[maxn],bel[maxn],sum[maxn],outt[maxn]; struct block { int l,r; } a[maxn]; inline int read() { int x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return x; } void doit(int l,int r) { for (int i=r; i>=l; i--) if (i+num[i]>a[bel[i]].r) sum[i]=1,outt[i]=i+num[i]; else sum[i]=sum[i+num[i]]+1,outt[i]=outt[i+num[i]]; } int main() { n=read(); m=sqrt(n); if (m*m<n) m++; int s=0; for (int i=1; i<=n; i++) num[i]=read(); for (int i=1; i<=n; i+=m) a[++s].l=i,a[s].r=i+m-1; if (s<m) a[++s].l=s*m+1,a[s].r=n; s=1; for (int i=1; i<=n; i++) { if (i>a[s].r) s++; bel[i]=s; } doit(1,n); Q=read(); while (Q--) { int x=read(),y=read()+1; if (x==1) { int ans=sum[y],x=outt[y]; for (int i=bel[y]; i<=m&&x<=n; i++) ans+=sum[x],x=outt[x]; printf("%d\n",ans); } else { int z=read(); num[y]=z; doit(a[bel[y]].l,a[bel[y]].r); } } return 0; }

 

2.lucky array(CF121E)

其实这题更简单,本该放在前面。

题目大意:区间加法,区间幸运数个数。

因为值域很小,我们发现在值域中的幸运数个数为30,所以我们先打个表,然后分块。

先统计每一个块内每一个数的出现次数,然后对于加法,我们还是打TAG,只不过在查询的时候要查询=(幸运数字-TAG)的个数

然后就好了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Rint register int
#define Temp template<typename T>
#define update(x,y,z) num[x][y]--,num[x][y+=z]++
using namespace std;
Temp inline void read(T &x) {
    x=0;T w=1,ch=getchar();
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    x*=w;
} 
const int t[30]={4,7,44,47,74,77,444,447,474,477,744,747,774,777,4444,4447,4474,4477
,4744,4747,4774,4777,7444,7447,7474,7477,7744,7747,7774,7777};
const int m=317*5;
const int maxn=1e5+10;
int n,q,cnt;
int a[maxn];
int num[105][maxn],id[maxn],low[maxn],high[maxn],add[maxn];
int vis[10010];
int main() {
    read(n);read(q);
    for (int i=1;i<=n;++i) {
        read(a[i]);
        id[i]=i/m+1;
        num[id[i]][a[i]]++;
    }
    cnt=id[n];
    for (int i=1;i<=cnt;++i) {
        low[i]=(i-1)*m;
        high[i]=i*m-1;
    }
    low[1]=1;high[cnt]=n;
    for (int i=0;i<30;++i) vis[t[i]]=1;
    while(q--) {
        char kind[10];
        int l,r,d;
        scanf("%s%d%d",kind,&l,&r);
        int lx=id[l],rx=id[r];
        if(*kind=='a') {
            scanf("%d",&d);
            if(lx==rx) {
                for (int i=l;i<=r;++i) update(lx,a[i],d);
            }
            else {
                for (int i=l;i<=high[lx];++i) update(lx,a[i],d);
                for (int i=lx+1;i<rx;++i) add[i]+=d;
                for (int i=low[rx];i<=r;++i) update(rx,a[i],d);
            }
        }
        else {
            int ans=0;
            if(lx==rx) {
                for (int i=l;i<=r;++i) ans+=vis[a[i]+add[lx]];
            }
            else {
                for (int i=l;i<=high[lx];++i) ans+=vis[a[i]+add[lx]];
                for (int i=lx+1;i<rx;++i) {
                    for (int j=0;j<30;++j) if(add[i]<=t[j]) ans+=num[i][t[j]-add[i]];
                }
                for (int i=low[rx];i<=r;++i) ans+=vis[a[i]+add[rx]];
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

part four-Ynoi(不提供代码,不然没啥意思)

1.luogu5397 天降之物(第四分块)

题目大意:将所有x变成y,求最小的|i-j|使得a[i]==x && a[j]==y。

定义size[x]为x出现次数.

 

by lxl(写了一遍题解发现自己写得太垃圾了)

2. 五彩斑斓的世界。(第二分块)

题目大意:把区间>x的数减去x,求区间l,r内x的出现次数,值域1e5

解法:

提示了值域1e5,时间复杂度肯定与值域有关。

 

这题明显有一个性质,就是所有数的最大值总是单调不增的。

 

考虑利用这个性质

 

然后,他是要把l,r内>x的数-x,可一转化为把所有数-x,然后把<0的数+x

当最大值>=x*2时,把(1,x)合并到(x+1,x*2)

否则把(x+1,v)合并到(1,v-x)

这个用并查集维护即可。

所以神仙多多指教啊

 

 

---恢复内容结束---

おすすめ

転載: www.cnblogs.com/zjjandrew/p/11302466.html