[离线+树状数组] HDU5869 Different GCD Subarray Query

来源:互联网 发布:ubuntu 挂载vmdk 编辑:程序博客网 时间:2024/05/10 19:02

对于这种询问有多少个不同的东西,有比较套路的方法是把询问离线,然后同种元素的贡献记在最近的位置上。比如 BZOJ1878 [SDOI2009]HH的项链
这题也是类似的做法,只是一个点上的元素不是1个而是log V个。所以就 O(nlog2n)

#include<cstdio>#include<cstring>#include<vector>#include<algorithm>#define Fir first#define Sec secondusing namespace std;const int maxn=100005,maxw=1000005;int n,Q,a[maxn],pos[maxw],ans[maxn];vector< pair<int,int> > q[maxn];vector< pair<int,int> > evn[maxn];int gcd(int x,int y){    return y==0?x:gcd(y,x%y);}void Pre(){    for(int i=1;i<=n;i++){        evn[i].push_back(make_pair(a[i],i));        for(int j=0,lst=a[i];j<evn[i-1].size();j++){            int _g=gcd(evn[i-1][j].Fir,a[i]);            if(_g!=lst) evn[i].push_back(make_pair(_g,evn[i-1][j].Sec)), lst=_g;        }    }}int bit[maxn];void Updata(int x,int val){    for(;x<=n;x+=(x&(-x))) bit[x]+=val; }int Query(int x){    int res=0;    for(;x;x-=(x&(-x))) res+=bit[x];    return res;}void Init(){    memset(bit,0,sizeof(bit));     memset(pos,0,sizeof(pos));    for(int i=1;i<=n;i++) q[i].clear(), evn[i].clear();}int main(){    while(scanf("%d%d",&n,&Q)==2){        Init();        for(int i=1;i<=n;i++) scanf("%d",&a[i]);        for(int i=1;i<=Q;i++){            int x,y; scanf("%d%d",&x,&y);            q[y].push_back(make_pair(x,i));        }        Pre();        for(int i=1;i<=n;i++){            for(int j=0;j<evn[i].size();j++)              if(pos[evn[i][j].Fir]<evn[i][j].Sec){                if(pos[evn[i][j].Fir]) Updata(pos[evn[i][j].Fir],-1);                Updata(evn[i][j].Sec,1);                pos[evn[i][j].Fir]=evn[i][j].Sec;             }            for(int j=0;j<q[i].size();j++) ans[q[i][j].Sec]=Query(i)-Query(q[i][j].Fir-1);        }        for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);            }     return 0;}
阅读全文
0 0