loj 数列分块入门 5 7 8

5

题意

给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间开方,区间求和。

思路

\(tag\)记录这一块是否已全为\(1\).

除分块外,还可用 树状数组+并查集(链表) 或者 线段树 做,见 Educational Codeforces Round 37 F

Code

#include <bits/stdc++.h>
#define maxn 50010
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long LL;
int n, blo, a[maxn], sum[maxn], bl[maxn];
bool tag[maxn];
void modify(int l, int r) {
    int temp;
    F(i, l, min((bl[l]+1)*blo, r+1)) sum[bl[l]] += (temp=sqrt(a[i]))-a[i], a[i] = temp;
    if (bl[l]!=bl[r]) F2(i, bl[r]*blo, r) sum[bl[r]] += (temp=sqrt(a[i]))-a[i], a[i] = temp;
    F(i, bl[l]+1, bl[r]) {
        if (tag[i]) continue;
        bool flag = true;
        F(j, i*blo, (i+1)*blo) {
            sum[i] += (temp=sqrt(a[j]))-a[j], a[j] = temp;
            if (temp > 1) flag = false;
        }
        tag[i] = flag;
    }
}
int query(int l, int r) {
    int ret = 0;
    F(i, l, min((bl[l]+1)*blo, r+1)) ret += a[i];
    if (bl[l]!=bl[r]) F2(i, bl[r]*blo, r) ret += a[i];
    F(i, bl[l]+1, bl[r]) ret += sum[i];
    return ret;
}
int main() {
    scanf("%d", &n); blo = sqrt(n);
    F(i, 0, n) scanf("%d", &a[i]), bl[i] = i/blo;
    int num = (n+blo-1) / blo;
    F(i, 0, num-1) {
        F(j, i*blo, (i+1)*blo) sum[i] += a[j];
    }
    F(j, (num-1)*blo, min(num*blo, n+1)) sum[num-1] += a[j];
    F(i, 0, n) {
        int op, l, r, c;
        scanf("%d%d%d%d", &op, &l, &r, &c); --l, --r;
        if (op) printf("%d\n", query(l, r));
        else modify(l, r);
    }
    return 0;
}

7

题意

给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间乘法,区间加法,单点询问。

思路

\(mtag\)记录每个块整体的倍数,用\(atag\)记录每个块整体的增量。
并且约定\(mtag\)优先级更高,即真实值为\(x*mtag+atag\)

对于不完整的块,先\(tag\)下放,再直接修改元素;

对于完整的块,修改\(tag\)

  1. \(+c\):即\((x*mtag+atag)+c=x*mtag+(atag+c)\),于是atag += x;
  2. \(\times c\):即\((x*mtag+atag)*c=x*(mtag*c)+(atag*c)\),于是atag *= x, mtag *= x

Code

#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define mod 10007
#define maxn 100010
#define maxm 1010
using namespace std;
typedef long long LL;
int n, blo, bl[maxn], a[maxn], mtag[maxm], atag[maxm];
void reset(int p) {
    F(i, p*blo, (p+1)*blo) {
        (((a[i]*=mtag[p])%=mod)+=atag[p])%=mod;
    }
    mtag[p] = 1, atag[p] = 0;
}
void work(int op, int l, int r, int c) {
    reset(bl[l]);
    F(i, l, min(r+1, (bl[l]+1)*blo)) {
        if (op) (a[i]*=c)%=mod;
        else (a[i]+=c)%=mod;
    }
    if (bl[l]!=bl[r]) {
        reset(bl[r]);
        F2(i, bl[r]*blo, r) {
            if (op) (a[i]*=c)%=mod;
            else (a[i]+=c)%=mod;
        }
    }
    F(i, bl[l]+1, bl[r]) {
        if (op) {
            (mtag[i]*=c)%=mod;
            (atag[i]*=c)%=mod;
        }
        else (atag[i]+=c)%=mod;
    }
}
int main() {
    scanf("%d", &n); blo = sqrt(n);
    F(i, 0, n) {
        scanf("%d", &a[i]);
        mtag[bl[i] = i/blo] = 1;
    }
    int num=(n+blo-1)/blo;
    F(i, 0, n) {
        int op, l, r, c;
        scanf("%d%d%d%d",&op,&l,&r,&c); --l, --r;
        if (op==2) printf("%d\n", (a[r]*mtag[bl[r]]%mod+atag[bl[r]])%mod);
        else work(op, l, r, c);
    }
    return 0;
}

8

题意

给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及询问等于一个数\(c\)的元素,并将这个区间的所有元素改为\(c\).

思路

类似上面两题。

\(tag\)维护这一块是否均为同一个数。

对于不完整的块:先下放\(tag\)后逐个统计修改元素

对于完整的块:直接针对\(tag\)进行统计和修改

Code

#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100010
#define maxm 1010
using namespace std;
typedef long long LL;
int a[maxn], bl[maxn], n, blo, tag[maxm];
bool flag[maxm];
void reset(int p) {
    if (!flag[p]) return;
    flag[p] = false;
    F(i, p*blo, min(n, (p+1)*blo)) a[i] = tag[p];
}
int query(int l, int r, int c) {
    int ret=0;
    if (flag[bl[l]]&&tag[bl[l]]==c) ret += min(r+1, (bl[l]+1)*blo)-l;
    else {
        reset(bl[l]);
        F(i, l, min(r+1, (bl[l]+1)*blo)) {
            ret += a[i]==c;
            a[i] = c;
        }
    }
    if (bl[l]!=bl[r]) {
        if (flag[bl[r]]&&tag[bl[r]]==c) ret += r-bl[r]*blo+1;
        else {
            reset(bl[r]);
            F2(i, bl[r]*blo, r) {
                ret += a[i]==c;
                a[i] = c;
            }
        }
    }
    F(i, bl[l]+1, bl[r]) {
        if (flag[i]) {
            if (tag[i]==c) ret += blo;
        }
        else {
            flag[i] = true;
            F(j, i*blo, (i+1)*blo) ret += a[j]==c;
        }
        tag[i] = c;
    }
    return ret;
}
int main() {
    scanf("%d", &n); blo = sqrt(n);
    F(i, 0, n) {
        scanf("%d", &a[i]);
        bl[i] = i/blo;
    }
    int num = (n+blo-1)/blo;
    F(i, 0, n) {
        int l, r, c;
        scanf("%d%d%d", &l,&r,&c);  --l, --r;
        printf("%d\n", query(l, r, c));
    }
    return 0;
}

posted @ 2018-02-26 17:20  救命怀  阅读(280)  评论(0编辑  收藏  举报