1. 程式人生 > 實用技巧 >莫隊

莫隊

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、QLR代表詢問你從第L支畫筆到第R支畫筆中共有幾種不同顏色的畫筆。

2、RPCol把第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;
}