day-15

莫队

普通莫队

注意顺序正确!!

codes
        for (int i = 1; i <= m; i++) {
            int pl = q[i].l, pr = q[i].r;
            while (l > pl) add(a[--l]);
            while (r < pr) add(a[++r]);
            while (l < pl) del(a[l++]);
            while (r > pr) del(a[r--]);
            ans[q[i].id] = cal(q[i].R) - cal(q[i].L - 1);
        }

值域二分

https://acm.hdu.edu.cn/showproblem.php?pid=6959

\(O(1)\)修改,\(O(sqrt(m))\)查询,在n,m等阶的情况下 ,复杂度平均只有\(O(n*sqrt(n)+ m*sqrt(n))\)比线段树等数据结构维护O(long(n))地修改查询优.

upd: 多组输入注意memset..

codes
const int maxn = 1e5 + 7;

int n, m, t, k = sqrt(maxn), a[maxn], num[maxn], sum[maxn], ans[maxn];

struct query {
    int l, r, L, R, id;
} q[maxn];

bool cmp(query a, query b) {
    if (a.l / k != b.l / k)
        return a.l / k < b.l / k;
    if ((a.l / k) & 1)
        return a.r < b.r;
    else
        return a.r > b.r;
}

void add(int x) {
    num[x]++;
    if (num[x] == 1)
        sum[x / k]++;
}

void del(int x) {
    num[x]--;
    if (num[x] == 0)
        sum[x / k]--;
}

int cal(int x) {
    int res = 0;
    for (int i = 0; i < x / k; i++)
        res += sum[i];
    for (int i = (x / k) * k; i <= x; i++)
        res += (num[i] >= 1);
    return res;
}

void solve() {
    cin >> t;
    while (t--) {
        memset(num, 0, sizeof num);
        memset(sum, 0, sizeof sum);
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = 1; i <= m; i++)
            cin >> q[i].l >> q[i].L >> q[i].r >> q[i].R, q[i].id = i;
        sort(q + 1, q + 1 + m, cmp);
        int l = 1, r = 0;
        for (int i = 1; i <= m; i++) {
            int pl = q[i].l, pr = q[i].r;
            while (l > pl) add(a[--l]);
            while (r < pr) add(a[++r]);
            while (l < pl) del(a[l++]);
            while (r > pr) del(a[r--]);
            ans[q[i].id] = cal(q[i].R) - cal(q[i].L - 1);
        }
        for (int i = 1; i <= m; i++)
            cout << ans[i] << "\n";
    }
}

带修莫队

https://www.luogu.com.cn/problem/P1903

  • 修改记录时间,修改值,修改后值 同时读入修改时进行修改,修改结束后还原

  • 分块大小:\(pow(n,2.0/3)\)

codes

const int maxn = 2e6 + 7;

int n, t, qn, m, k, a[maxn], ans[maxn], num[maxn], sum;
char op;

struct query {
    int l, r, t, id;
} q[maxn];

struct change {
    int pl, val, oval;
} chg[maxn];

bool cmp(query a, query b) {
    if (a.l / k != b.l / k) return a.l / k < b.l / k;
    if (a.r / k != b.r / k) return a.r / k < b.r / k;
    return a.t < b.t;
}

void add(int x) {
    if (x == 0)
        return;
    num[x]++;
    sum += (num[x] == 1);
}


void del(int x) {
    if (x == 0)
        return;
    num[x]--;
    sum -= (num[x] == 0);
}

int l = 1, r = 0, tn = 0;

void addchange(int t) {
    int pl = chg[t].pl, val = chg[t].val;
    if (pl >= l && pl <= r)
        add(val), del(a[pl]);
    a[pl] = val;
}

void delchange(int t) {
    int pl = chg[t].pl, val = chg[t].oval;
    if (pl >= l && pl <= r)
        add(val), del(a[pl]);
    a[pl] = val;
}

void solve() {
    cin >> n >> m;
    k = pow(n, 2.0 / 3);
    for (int i = 1; i <= n; i++) cin >> a[i];

    for (int i = 1, l, r; i <= m; i++) {
        cin >> op >> l >> r;
        if (op == 'R') chg[++t].pl = l, chg[t].val = r, chg[t].oval = a[l], a[l] = r;
        else q[++qn].l = l, q[qn].r = r, q[qn].t = t, q[qn].id = qn;
    }

    for (int i = t; i >= 1; i--) a[chg[i].pl] = chg[i].oval;

    sort(q + 1, q + 1 + qn, cmp);

    for (int i = 1; i <= qn; i++) {
        int L = q[i].l, R = q[i].r, T = q[i].t;

        while (tn < T) addchange(++tn);
        while (tn > T) delchange(tn--);
        while (l > L) add(a[--l]);
        while (r < R) add(a[++r]);
        while (l < L) del(a[l++]);
        while (r > R) del(a[r--]);

        ans[q[i].id] = sum;
    }
    for (int i = 1; i <= qn; i++)
        cout << ans[i] << "\n";
}

https://codeforces.com/contest/1234/problem/D

  • 修改添加和删除的代码很重要..
  • 可以树状数组写..
codes
const int maxn = 1e5 + 7;

int n, t, m, k, l, r;

char s[maxn], ch;
int ans[maxn], sum, num[200];


int qn;
struct query {
    int l, r, id, t;
} q[maxn];

int tn;
struct change {
    int pl;
    char val, oval;
} c[maxn];

bool cmp(query a, query b) {
    if (a.l / k != b.l / k) return a.l / k < b.l / k;
    if (a.r / k != b.r / k) return a.r / k < b.r / k;
    return a.t < b.t;
}


void add(char ch) {
    num[ch]++;
    if (num[ch] == 1)
        sum++;
}

void del(char ch) {
    num[ch]--;
    if (num[ch] == 0)
        sum--;
}

void addchange(int t) {
    int pl = c[t].pl, val = c[t].val;
    if (pl >= l && pl <= r)
        add(val), del(s[pl]);
    s[pl] = val;
}

void delchange(int t) {
    int pl = c[t].pl, val = c[t].oval;
    if (pl >= l && pl <= r)
        add(val), del(s[pl]);
    s[pl] = val;
}

void solve() {
    cin >> (s + 1) >> m;
    k = pow(strlen(s + 1), 2.0 / 3);
    for (int i = 1; i <= m; i++) {
        cin >> n;
        if (n == 1) {
            cin >> n >> ch;
            c[++tn].pl = n, c[tn].val = ch, c[tn].oval = s[n];
            s[n] = ch;
        } else {
            cin >> l >> r;
            qn++, q[qn] = {l, r, qn, tn};
        }
    }

    for (int i = tn; i >= 1; i--)
        s[c[i].pl] = c[i].oval;

    sort(q + 1, q + 1 + qn, cmp);

    l = 1, r = 0, t = 0;

    for (int i = 1; i <= qn; i++) {
        int pl = q[i].l, pr = q[i].r, pt = q[i].t;
        while (t < pt) addchange(++t);
        while (t > pt) delchange(t--);
        while (l > pl) add(s[--l]);
        while (r < pr) add(s[++r]);
        while (l < pl) del(s[l++]);
        while (r > pr) del(s[r--]);
        ans[q[i].id] = sum;
    }
    for (int i = 1; i <= qn; i++)
        cout << ans[i] << endl;
}
## 树上莫队 ## 回滚莫队 ## 其他技巧
posted @ 2021-07-27 19:30  naymi  阅读(29)  评论(0)    收藏  举报