莫队算法

来源:互联网 发布:网络重载连接器hdc cm 编辑:程序博客网 时间:2024/05/01 23:28

题目链接
题意:给定区间内的值,k次查询,问L到R之间有多少个不同的数;

/*莫队算法离线查询区间问题,知道L和R可以O(1)推出(L+1,R),(L-1,R),(L,R+1),(L,R-1)的值的问题都可以用莫队算法排序后离线求解*/#include<cstdio>#include<queue>#include<vector>#include<cmath>#include<cstring>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int maxn=1e6+10;int x[maxn],block[maxn];struct zp{    int l,r,id;} query[maxn];int cmp(zp a,zp b)//按照莫队算法的排序方式可将区间查询的平均复杂度优化为n*sqrt(n){    if(block[a.l]!=block[b.l]) return a.l<b.l;    else return a.r<b.r;}int vis[maxn],ans[maxn];void solve(int n)//暴力求解{    memset(vis,0,sizeof(vis));    int sum=1;    int l=query[0].l,r=query[0].l;    vis[x[l]]=1;    for(int i=0; i<n; i++)    {        while(l<query[i].l)        {            vis[x[l]]--;            if(vis[x[l]]==0)                sum--;            l++;        }        while(l>query[i].l)        {            l--;            if(vis[x[l]]==0)                sum++;            vis[x[l]]++;        }        while(r<query[i].r)        {            r++;            if(vis[x[r]]==0)                sum++;            vis[x[r]]++;        }        while(r>query[i].r)        {            vis[x[r]]--;            if(vis[x[r]]==0)                sum--;            r--;        }        ans[query[i].id]=sum;    }}int main(){    int n;    while(~scanf("%d",&n))    {        int sqt=sqrt(n);        for(int i=1; i<=n; i++)        {            scanf("%d",&x[i]);            block[i]=(i-1)/sqt;//分块        }        int k;        scanf("%d",&k);        for(int i=0; i<k; i++)//存储离线查询        {            scanf("%d%d",&query[i].l,&query[i].r);            query[i].id=i;        }        sort(query,query+k,cmp);//莫队算法的关键所在        solve(k);//暴力求解        for(int i=0;i<k;i++)            printf("%d\n",ans[i]);    }}
0 0
原创粉丝点击