Live2D

莫队

1、普通莫队

SP3267 DQUERY - D-query

题意简明易懂:给你一个长度不大于n5×10^5的序列,其中数值都小于等于10^6,有m5×10^5次询问,每次询问区间[l,r]中数值个数(也就是去重后数字的个数)。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

#define maxn 1010000
#define maxb 1010
int aa[maxn], cnt[maxn], belong[maxn];
int n, m, size, bnum, now, ans[maxn];
struct query {
    int l, r, id;
} q[maxn];

int cmp(query a, query b) {
    return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
#define isdigit(x) ((x) >= '0' && (x) <= '9')
int read() {
    int res = 0;
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar();
    return res;
}
void printi(int x) {
    if(x / 10) printi(x / 10);
    putchar(x % 10 + '0');
}

int main() {
    scanf("%d", &n);
    size = sqrt(n);
    bnum = ceil((double)n / size);
    for(int i = 1; i <= bnum; ++i) 
        for(int j = (i - 1) * size + 1; j <= i * size; ++j) {
            belong[j] = i;
        }
    for(int i = 1; i <= n; ++i) aa[i] = read(); 
    m = read();
    for(int i = 1; i <= m; ++i) {
        q[i].l = read(), q[i].r = read();
        q[i].id = i;
    }
    sort(q + 1, q + m + 1, cmp);
    int l = 1, r = 0;
    for(int i = 1; i <= m; ++i) {
        int ql = q[i].l, qr = q[i].r;
        while(l < ql) now -= !--cnt[aa[l++]];
        while(l > ql) now += !cnt[aa[--l]]++;
        while(r < qr) now += !cnt[aa[++r]]++;
        while(r > qr) now -= !--cnt[aa[r--]];
        ans[q[i].id] = now;
    }
    for(int i = 1; i <= m; ++i) printi(ans[i]), putchar('\n');
    return 0;
}

 

带修莫队

Luogu P1903 [国家集训队]数颜色 / 维护队列

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

2、 P Col把第PP支画笔替换为颜色Col。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int a[N], cnt[N<<1], ans[N], belong[N];
struct query {int l, r, time, id;} q[N];
struct modify {int pos, color, last;} c[N];
int cntq, cntc, n, m, size, bnum;
inline int cmp(query a, query b) {
    return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.r] ^ belong[b.r]) ? belong[a.r] < belong[b.r] : a.time < b.time);
}
inline int read() {
    int res = 0;
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar();
    return res;
}
int main() {
    n = read(), m = read();
    size = pow(n, 2.0 / 3.0);
    bnum = ceil((double)n / size);
    for (int i = 1; i <= bnum; ++i) 
        for (int j = (i-1)*size+1; j <=i*size; ++j) belong[j]=i;
    for(int i = 1; i <= n; ++i) a[i] = read();
    for(int i = 1; i <= m; ++i) {
        char op;
        cin>>op;
        if (op == 'Q') {
            q[++cntq].l = read();
            q[cntq].r = read();
            q[cntq].time = cntc;
            q[cntq].id = cntq;
        }
        else if(op == 'R') {
            c[++cntc].pos = read();
            c[cntc].color = read();
        }
    }
    sort(q + 1, q + cntq + 1, cmp);
    int l = 1, r = 0, time = 0, now = 0;
    for(int i = 1; i <= cntq; ++i) {
        int ql = q[i].l, qr = q[i].r, qt = q[i].time;
        while (l < ql) now -= !--cnt[a[l++]];
        while (l > ql) now += !cnt[a[--l]]++;
        while (r < qr) now += !cnt[a[++r]]++;
        while (r > qr) now -= !--cnt[a[r--]];
        while (time < qt) {
            ++time;
            if (ql <= c[time].pos && c[time].pos <= qr) now-= !--cnt[a[c[time].pos]]-!cnt[c[time].color]++;
            swap(a[c[time].pos],c[time].color);
        }
        while (time > qt) {
            if (ql <= c[time].pos && c[time].pos <= qr) now-= !--cnt[a[c[time].pos]]-!cnt[c[time].color]++;
            swap(a[c[time].pos], c[time].color);
            --time;
        }
        ans[q[i].id] = now;
    }
    for (int i = 1; i <= cntq; ++i) 
        printf("%d\n", ans[i]);
    return 0;
}

cf940f

给出一个长度为N序列
需要支持两种操作:
1、定义一个区间的值为:这段区间任意元素出现次数的集合的mex,给出l,r求原串中[l,r]这段区间的值
2、修改某个点的值
对mex的定义与SG函数中是相同的,表示一个自然数集中未出现的最小的整数。
例如:1321222这个序列的值为3:
3出现了1次,1出现了2次,2出现了4次,集合中的数为0,1,2,4(所有除了这三个数以外的[0,10^9]的数均未出现,所以为0)
NM10^5

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m,blo,temp,nn,a[N],b[N], bl[N], cnt[N<<1], num[N<<1], l, r, mp[N<<1], tot, ans[N], cnt1, cnt2, tim;
struct query {int l,r,tim,id; }q[N];
struct modify { int x, val, last; }c[N];
inline int read() {
    int x=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return x;
}
inline int cmp(query a, query b) {
    return (bl[a.l] ^ bl[b.l]) ? bl[a.l] < bl[b.l] : ((bl[a.r] ^ bl[b.r]) ? bl[a.r] < bl[b.r] : a.tim < b.tim);
}
inline void add(int x) { --num[cnt[x]]; ++num[++cnt[x]]; }
inline void del(int x) { --num[cnt[x]]; ++num[--cnt[x]]; }
inline void change(int x, int y) {
    if (l<=x && x<=r) del(a[x]), add(y);
    a[x] = y;
}
inline void discrete() {
    sort(mp+1, mp+tot+1);
    nn=unique(mp+1, mp+tot+1)-mp;
    for (int i=1;i<=n;i++) a[i]=lower_bound(mp+1,mp+nn+1,a[i])-mp+1;
    for (int i=1;i<=cnt2;i++) 
        c[i].last=lower_bound(mp+1,mp+nn+1,c[i].last)-mp+1, c[i].val=lower_bound(mp+1,mp+nn+1,c[i].val)-mp+1;
}
int main() {
    n=read(),m=read();
    blo = pow(n, 2.0/3.0);
    for (int i=1;i<=n;i++) a[i]=read(), b[i] = mp[++tot] = a[i], bl[i]=(i-1)/blo;
    for (int i=1,op,l,r;i<=m;i++) {
        op=read(),l=read(),r=read();
        if (op==1) q[++cnt1] = {l, r, tim, cnt1};
        else ++tim, c[++cnt2] = {l, r, b[l]}, b[l] = r, mp[++tot] = r;
    }
    discrete();
    sort(q+1, q+cnt1+1,cmp);
    r=0, l=1;
    num[0]=nn+1; tim=0;
    for (int i=1;i<=cnt1;i++) {
        while (r<q[i].r) add(a[++r]);
        while (l>q[i].l) add(a[--l]);
        while (r>q[i].r) del(a[r--]);
        while (l<q[i].l) del(a[l++]);
        while (tim<q[i].tim) tim++, change(c[tim].x, c[tim].val);
        while (tim>q[i].tim) change(c[tim].x, c[tim].last), --tim;
        int tmp=0;
        while (num[tmp]) ++tmp;
        ans[q[i].id] = tmp;
    }
    for (int i=1;i<=cnt1;i++) printf("%d\n", ans[i]);
    return 0;
}

树上莫队

SP10707 COT2 - Count on a tree II

题目描述

给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数。

#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
inline int read() {
    int x=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return x;
}
int n, m,belong[N], block, a[N], b[N];
vector<int>v[N];
struct query {int l, r, id, lca, ans;}q[N];
inline int cmp(query a, query b) {
    return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
inline void Discretization() {
    sort(b + 1, b + N + 1);
    int num = unique(b + 1, b + N + 1) - b - 1;
    for(int i = 1; i <= N; i++) a[i] = lower_bound(b + 1, b + num + 1, a[i]) - b;    
}
int deep[N], top[N], fa[N], siz[N], son[N], st[N], ed[N], pot[N], tot;
void dfs1(int x, int _fa) {
    fa[x] = _fa; siz[x] = 1;
    st[x] = ++ tot; pot[tot] = x; 
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(deep[to]) continue;
        deep[to] = deep[x] + 1;
        dfs1(to, x);
        siz[x] += siz[to];
        if(siz[to] > siz[son[x]]) son[x] = to;
    }
    ed[x] = ++tot; pot[tot] = x;
}
void dfs2(int x, int topfa) {
    top[x] = topfa;
    if(!son[x]) return ;
    dfs2(son[x], topfa);
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(top[to]) continue;
            dfs2(to, to);
    }
}
inline int Lca(int x, int y) {
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    return deep[x] < deep[y] ? x : y;
}
int Ans, t[N], vis[N], happen[N];
inline void add(int x) {
    if (++happen[x] == 1) Ans++;
}
inline void del(int x) {
    if (--happen[x] == 0) Ans--;
}
inline void change(int x) {
    vis[x] ? del(a[x]) : add(a[x]); vis[x] ^= 1;
}
int main() {
    n = read(); m = read();
    block = sqrt(n);
    for (int i = 1; i <= n; i++) a[i] = b[i] = read();
    for (int i = 1; i <= n * 2; i++) belong[i] = i / block + 1;
    Discretization();
    for (int i = 1; i < n; i++) {
        int x = read(), y = read();
        v[x].push_back(y); v[y].push_back(x);
    }
    deep[1] = 1;
    dfs1(1, 0);
    dfs2(1, 1);
    
    for (int i = 1; i <= m; i++) {
        int x = read(), y = read();
        if (st[x] > st[y]) swap(x, y);
        int _lca =Lca(x, y);
        q[i].id = i;
        if (_lca == x) q[i].l = st[x], q[i]. r = st[y];
        else q[i].l = ed[x], q[i].r = st[y], q[i].lca = _lca;
    }
    
    sort(q + 1, q + m + 1,cmp);
    int l = 1, r = 0;
    for(int i = 1; i <= m; i++) {
        while(l < q[i].l) change(pot[l]), l++;
        while(l > q[i].l) l--, change(pot[l]);
        while(r < q[i].r) r++, change(pot[r]);
        while(r > q[i].r) change(pot[r]), r--;
        if (q[i].lca) change(q[i].lca);
        q[i].ans = Ans;
        if (q[i].lca) change(q[i].lca);
    }
    for(int i = 1; i <= m; i++) t[q[i].id] = q[i].ans;
    for(int i = 1; i <= m; i++)
        printf("%d\n", t[i]);
    return 0;
}

树上带修莫队   

P4074 [WC2013]糖果公园

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
#define rg register
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,m,Q,cnte,cnt1,cnt2,tim;
int head[N],val[N],w[N],a[N],b[N],dep[N];
int f[N][20];
int bl[N<<1],cnt[N];
ll nowans,ans[N];
bool vis[N];
inline int read() {
    int x=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return x;
}
struct edge{int to,nxt;}e[N<<1];
inline void add(int u,int v) {
    e[++cnte].nxt=head[u];
    head[u]=cnte;
    e[cnte].to=v;
}
int ouler[N<<1],st[N],ed[N];
inline void dfs(int x,int fa) {
    for (rg int i=1;i<=18;i++)
        f[x][i]=f[f[x][i-1]][i-1];
    dep[x]=dep[fa]+1;
    ouler[++tim]=x;st[x]=tim;
    for (rg int i=head[x];i;i=e[i].nxt) {
        int y=e[i].to;
        if(y==fa)continue;
        f[y][0]=x;dfs(y,x);
    }
    ouler[++tim]=x;ed[x]=tim;
}
inline int lca(int x,int y) {
    if (dep[x]>dep[y]) swap(x,y);
    for (int i=18;i>=0;i--) 
        if (dep[f[y][i]]>=dep[x]) y=f[y][i];
    if (x==y) return x;
    for (rg int i=18;i>=0;i--)
        if (f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
struct query{int l,r,lca,id,tim;}q[N];
struct modify{int pos,last,now;}c[N];
inline int cmp(query a, query b) {
    return (bl[a.l] ^ bl[b.l]) ? bl[a.l] < bl[b.l] : ((bl[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
inline void del(int c) {nowans-=1ll*val[c]*w[cnt[c]--];}
inline void add(int c) {nowans+=1ll*val[c]*w[++cnt[c]];}
inline void change(int pos,int k) {
    if (vis[pos]) del(a[pos]),add(k);
    a[pos]=k;
}
inline void work(int pos) {
    if (vis[ouler[pos]]) del(a[ouler[pos]]);
    else add(a[ouler[pos]]);
    vis[ouler[pos]]^=1;
}
int main() {
    n=read(),m=read(),Q=read();
    for (rg int i=1;i<=m;i++) val[i]=read();
    for (rg int i=1;i<=n;i++) w[i]=read();
    for (rg int i=1;i<n;i++) {
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    dfs(1,0);
    for (rg int i=1;i<=n;i++) a[i]=b[i]=read();
    for (rg int i=1;i<=Q;i++) {
        int op=read(),x=read(),y=read();
        if (op) q[++cnt1]=(query){x,y,0,cnt1,cnt2};
        else c[++cnt2]=(modify){x,b[x],y},b[x]=y;
    }
    for (rg int i=1;i<=Q;i++) {
        if (st[q[i].l]>st[q[i].r]) swap(q[i].l,q[i].r);
        int z=lca(q[i].l,q[i].r);
        if (z==q[i].l) q[i].l=st[q[i].l],q[i].r=st[q[i].r];
        else q[i].l=ed[q[i].l],q[i].r=st[q[i].r],q[i].lca=z;
    }
    int blo=pow(2*n,2.0/3.0);
    for (rg int i=1;i<=2*n;i++) bl[i]=(i-1)/blo+1;
    sort(q+1,q+cnt1+1,cmp);
    int l=1,r=0,tim1=0;
    for (rg int i=1;i<=cnt1;i++) {
        while (tim1<q[i].tim) change(c[tim1+1].pos,c[tim1+1].now),tim1++;
        while (tim1>q[i].tim) change(c[tim1].pos,c[tim1].last),tim1--;
        while (l<q[i].l) work(l++);
        while (l>q[i].l) work(--l);
        while (r<q[i].r) work(++r);
        while (r>q[i].r) work(r--);
        if (q[i].lca) work(st[q[i].lca]);
        ans[q[i].id]=nowans;
        if (q[i].lca) work(st[q[i].lca]);
    }
    for (rg int i=1;i<=cnt1;i++) printf("%lld\n",ans[i]);
    return 0;
}

 


回滚莫队

AT1219 歴史の研究

给定一个长度为n的序列,离线询问m个问题,每次回答区间内元素权值乘以元素出现次数的最大值。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n,m,sz,T,raw[N],val[N],t,cnt[N],cnt_[N];
int bl[N],L[N],R[N];
long long ans[N],Max,a[N];
struct query{int l,r,id;}q[N];
inline int cmp(query a, query b) {
    return (bl[a.l] ^ bl[b.l]) ? bl[a.l] < bl[b.l] : a.r < b.r; 
}
inline void discrete() {
    sort( raw+1 , raw+t+1 );
    t = unique( raw+1 , raw+t+1 ) - (raw+1);
    for (int i=1;i<=n;i++)
        val[i] = lower_bound( raw+1 , raw+t+1 , a[i] ) - raw;
}
inline void add(int p,long long &maxval) {
    cnt[val[p]]++;
    maxval = max( maxval , 1ll * cnt[val[p]] * a[p] );
}
inline void del(int p) {cnt[val[p]]--;}
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%lld",&a[i]) , raw[++t] = a[i];
    for (int i=1;i<=m;i++)
        scanf("%d%d",&q[i].l,&q[i].r) , q[i].id = i;
    discrete();
    sz = sqrt(n) , T = n/sz;
    for (int i=1;i<=T;i++) {
        if ( i * sz > n ) break;
        L[i] = (i-1) * sz + 1;
        R[i] = i * sz;
    }
    if ( R[T] < n ) T++ , L[T] = R[T-1] + 1 , R[T] = n;
    for (int i=1;i<=T;i++)
        for (int j=L[i];j<=R[i];j++)
            bl[j] = i;
    sort( q+1 , q+m+1 , cmp );
    int l = 1 , r = 0 , last = 0;
    for (int i=1;i<=m;i++) {
        if ( bl[q[i].l] == bl[q[i].r] ) {
            for (int j=q[i].l;j<=q[i].r;j++) cnt_[val[j]]++;
            long long temp = 0;
            for (int j=q[i].l;j<=q[i].r;j++) 
                temp = max( temp , 1ll * cnt_[val[j]] * a[j] );
            for (int j=q[i].l;j<=q[i].r;j++) cnt_[val[j]]--;
            ans[ q[i].id ] = temp; 
            continue; 
        }
        if ( last ^ bl[q[i].l] ) {
            while ( r > R[bl[q[i].l]] ) del(r--);
            while ( l < R[bl[q[i].l]]+1 ) del(l++);
            Max = 0 , last = bl[q[i].l];
        }
        while ( r < q[i].r ) add(++r,Max);
        long long temp = Max; int  l_ = l;
        while ( l_ > q[i].l ) add(--l_,temp);
        while ( l_ < l ) del(l_++);
        ans[ q[i].id ] = temp;
    }
    for (int i=1;i<=m;i++) printf("%lld\n",ans[i]);
    return 0;
}

 

posted @ 2020-08-13 12:20  γひん0ΖΖƦ  阅读(259)  评论(0编辑  收藏  举报