莫队模板

旧街凉风 提交于 2020-02-05 01:29:42

转自:https://www.cnblogs.com/WAMonster/p/10118934.html
不需要修改值的莫队
题目链接:https://vjudge.net/problem/SPOJ-DQUERY#author=0
题意:求区间内不同的数的个数

把整个区间分块后排序,用双指针移动解决。
指针移动优化

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--]];

还可以加读入输出优化
最好把分块的大小改成 n23\frac{2}{3} 会更快 n\sqrt{n}可能会退化

#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
const int maxn=15e5+5;
const int maxm=1e6+5;
int aa[maxn],cnt[maxm],ans[maxn],belong[maxn],now;
struct NODE
{
    int l,r,id;
} q[maxn];
int cmp(NODE a, NODE 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);
}
int main()
{
    int n,m;
    scanf("%d",&n);
    int sz=sqrt(n);
    int bnum=ceil((double)n/sz);
    for(int i=1; i<=bnum; i++)
    {
        for(int j=(i-1)*sz+1; j<=i*sz; j++)
        {
            belong[j]=i;

        }
    }
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&aa[i]);
    }
    scanf("%d",&m);
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&q[i].l,&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 ql=q[i].l,qr=q[i].r;
        while(l<ql)
        {
            --cnt[aa[l]];
            if(!cnt[aa[l]])
                now--;
            l++;
        }
        while(l>ql)
        {
            l--;
            if(!cnt[aa[l]])
                now++;
            ++cnt[aa[l]];
        }
        while(r<qr)
        {
            r++;
            if(!cnt[aa[r]])
                now++;
            ++cnt[aa[r]];
        }
        while(r>qr)
        {
            --cnt[aa[r]];
            if(!cnt[aa[r]])
                now--;
            r--;
        }
        ans[q[i].id]=now;
    }
    for(int i=1; i<=m; i++)
        printf("%d\n",ans[i]);
    return 0;
}

带单点修改的莫队
题目链接:https://vjudge.net/problem/HYSBZ-2120
单点修改就多了一个指针time,表示当前询问所在的时间顺序,每次查询时time移动并且修改cnt,同时更改值。
排序函数也需要修改一下。
time指针优化

        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;
        }
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
const int maxn=1e4+5;
const int maxm=1e6+5;
int a[maxn],cnt[maxm],ans[maxn],belong[maxn];
struct query
{
    int l,r,time,id;
} q[maxn];
struct modify
{
    int pos,color,last;
} c[maxn];
int cntq,cntc,n,m,sz,bnum;
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);
}
int main()
{
    scanf("%d%d",&n,&m);
    getchar();
    sz=pow(n,2.0/3.0);
    bnum=ceil((double)n/sz);
    for(int i=1; i<=bnum; i++)
    {
        for(int j=(i-1)*sz+1; j<=i*sz; j++)
        {
            belong[j]=i;
        }
    }
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        getchar();
    }
    for(int i=1; i<=m; i++)
    {
        char ss[100];
        int x,y;
        scanf("%s",ss);
        getchar();
        scanf("%d%d",&x,&y);
        getchar();
        if(ss[0]=='Q')
        {
            q[++cntq].l=x;
            q[cntq].r=y;
            q[cntq].time=cntc;
            q[cntq].id=cntq;
        }
        else if(ss[0]=='R')
        {
            c[++cntc].pos=x;
            c[cntc].color=y;
        }
    }
    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)
        {
            --cnt[a[l]];
            if(!cnt[a[l]])
                now--;
            l++;
        }
        while(l>ql)
        {
            l--;
            if(!cnt[a[l]])
                now++;
            ++cnt[a[l]];
        }
        while(r<qr)
        {
            r++;
            if(!cnt[a[r]])
                now++;
            ++cnt[a[r]];
        }
        while(r>qr)
        {
            --cnt[a[r]];
            if(!cnt[a[r]])
                now--;
            r--;
        }
        while(time<qt)
        {
            ++time;
            if(ql<=c[time].pos&&c[time].pos<=qr)
            {
                cnt[a[c[time].pos]]--;
                if(!cnt[a[c[time].pos]])
                    now--;
                if(!cnt[c[time].color])
                    now++;
                cnt[c[time].color]++;
            }
            swap(a[c[time].pos],c[time].color);
        }
        while(time>qt)
        {
            if(ql<=c[time].pos&&c[time].pos<=qr)
            {
                cnt[a[c[time].pos]]--;
                if(!cnt[a[c[time].pos]])
                    now--;
                if(!cnt[c[time].color])
                    now++;
                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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!