HDU 5286 wyh2000 and sequence 分块,贡献,好题

来源:互联网 发布:企业展示型网站源码 编辑:程序博客网 时间:2024/05/06 06:22
HDU 5286
题意:给出长度为n的序列a,
Q次在线询问[L,R],当[L,R]有k个不同的数c1,c2..ck,并且c[i]出现b[i]次.
每次询问,求累加和[i=1...k](c[i]^b[i])
n,Q<=5e4, a[i]<=1e9.


能离线的话就直接莫队搞一搞 然而本题要求在线..
在线就分块呗,O(n*sqrt(n))预处理出res[i][j] 第i块到第j块的ans (预处理方法就是更新新加入的数的贡献即可)
询问时,ans先计入中间块.
然后以此把头尾两块中元素x的贡献计入到ans中(--++)

此时需要知道x的在中间块中的出现次数.在用pre[i][j],第j个元素在前i块中的出现次数 nsqrt预处理一下即可.

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=5e4+5,M=3e2+5,mod=1e9+7;ll a[N],b[N],x[N],res[M][M],d[N];int C[M][N],n,m,s,sn,c[N];vector<ll> v[N];//powvoid init(){    memset(C,0,sizeof(C));    scanf("%d%d",&n,&m);    for(int i=0;i<n;i++)        scanf("%lld",&a[i]),b[i]=a[i];    sort(b,b+n);    int cnt=unique(b,b+n)-b;    for(int i=0;i<n;i++)        x[i]=lower_bound(b,b+cnt,a[i])-b;    for(int i=0;i<cnt;i++)        v[i].clear();    for(int i=0;i<cnt;i++)        v[i].push_back(0);//    for(int i=0;i<n;i++)    {        ll t=v[x[i]][v[x[i]].size()-1];        if(v[x[i]].size()==1)            t=1;        t=t*a[i]%mod;        v[x[i]].push_back(t);    }    s=sqrt(n),sn=n/s;    if(n%s) sn++;    for(int i=0;i<sn;i++)    {        ll ans=0;        memset(c,0,sizeof(c));        for(int j=i*s;j<n;j++)        {            int num=j/s;//num'th block            ans=(ans-v[x[j]][c[x[j]]]+v[x[j]][++c[x[j]]]+mod)%mod;            res[i][num]=ans;        }    }    for(int i=0;i<sn;i++)        for(int j=0;j<(i+1)*s && j<n;j++)            C[i][x[j]]++;//C[i][j] the fre of val j appears in pre i's block.}void work(){    ll ans=0;    memset(c,0,sizeof(c));    while(m--)    {        ll l,r,ll,rr,cnt=0;        scanf("%lld%lld",&ll,&rr);        l = min((ll ^ ans) % n, (rr ^ ans) % n);        r = max((ll ^ ans) % n, (rr ^ ans) % n);        ans=0;        int num1=l/s+1,num2=r/s-1;//middle blocks        if(num2>=num1)            ans=res[num1][num2];        if(l/s!=r/s)        {            for(int i=l;i<num1*s;i++)                d[cnt++]=x[i];            for(int i=(num2+1)*s;i<=r;i++)                d[cnt++]=x[i];        }        else            for(int i=l;i<=r;i++)                d[cnt++]=x[i];        for(int i=0;i<cnt;i++)        {            if(c[d[i]]==0&&num2>=num1)//d[i]在mid块中的出现次数                c[d[i]]+= C[num2][d[i]]-C[num1-1][d[i]];            ans=(ans-v[d[i]][c[d[i]]]+v[d[i]][++c[d[i]]]+mod)%mod;        }        for(int i=0;i<cnt;i++)            c[d[i]]=0;        printf("%lld\n",ans);    }}int main(){    int T;    cin>>T;    while(T--)        init(),work();    return 0;}


原创粉丝点击