• 莫队


    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('
    ');
        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
    ", 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
    ", 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
    ", 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
    ",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
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    javascript中new Date()的浏览器兼容性问题
    js 时间格式化
    HTML5 JS实现搜索匹配功能
    PHP中preg_match正则匹配的/u /i /s是什么意思
    微信开放接口获取用户昵称保存到MySQL中为空白
    linux下源码安装软件
    格式化MYSQL时间戳函数FROM_UNIXTIME
    Zabbix-proxy安装部署
    使用ss命令对tcp连接数和状态的监控性能优化
    Zabbix使用netstat监控会话
  • 原文地址:https://www.cnblogs.com/zzrblogs/p/13495667.html
Copyright © 2020-2023  润新知