hdu 5869 Different GCD Subarray Query 离线+树状数组

来源:互联网 发布:下载动态壁纸软件 编辑:程序博客网 时间:2024/07/17 03:03

题意:给你n个数,每次查询[l,r]区间里所有子区间不同gcd的个数。

我们先来看如何查询区间不同数的个数: spoj D-query 区间不同数个数 主席树||离线+树状数组

上面这道题讨论的是单个点,既对答案有贡献的是单个点,而这里是子区间要怎么处理。

同理,对每个gcd有多个子区间,定义子区间左端点为子区间大小,那么只有最大的那个子区间才是有效的。

这里还要用到gcd性质,离线后对当前点它只能和前i-1个后缀取gcd,以及它自己作为gcd,这里只会产生log(a[i])个gcd。

所以保存下来暴力枚举即可。

ps:就统计区间不同数来说,还有在线做法,既对每个前缀建一棵线段树(主席树)hdu 5790 prefix 主席树

#include <iostream>#include <cstdio>#include <cstdlib>#include <map>#include <algorithm>using namespace std;const int maxn=1e5+7;struct node{    int l,r,id;    bool operator<(node t)const {        return r<t.r;    }}q[maxn];map<int,int> mp[3];map<int,int> ::iterator it;int a[maxn];int ans[maxn];int data[maxn];int sum(int i){    int s=0;    while(i>0){        s+=data[i];        i-=i&-i;    }    return s;}void add(int i,int x){    while(i<maxn){        data[i]+=x;        i+=i&-i;    }}int main(){    int n,m;    while(~scanf("%d%d",&n,&m)){        fill(data,data+n+5,0);        for(int i=0;i<3;i++)        mp[i].clear();        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);        }        for(int i=1;i<=m;i++){            scanf("%d%d",&q[i].l,&q[i].r);            q[i].id=i;        }        sort(q+1,q+m+1);for(int i=1;i<=m;i++)        q[0].r=0;        for(int i=1;i<=m;i++){            for(int j=q[i-1].r+1;j<=q[i].r;j++){                for(it=mp[(j&1)^1].begin();it!=mp[(j&1)^1].end();it++){                    int tmp=__gcd(a[j],it->first);                    mp[j&1][tmp]=1;                    if(!mp[2][tmp])mp[2][tmp]=mp[2][it->first],add(mp[2][it->first],1);                    else if(mp[2][it->first]>mp[2][tmp]){                        add(mp[2][tmp],-1);                        add(mp[2][it->first],1);                        mp[2][tmp]=mp[2][it->first];                    }                }                mp[j&1][a[j]]=1;                if(mp[2][a[j]]){                    add(mp[2][a[j]],-1);                    add(j,1);                }                else add(j,1);                mp[2][a[j]]=j;                mp[(j&1)^1].clear();            }            ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1);        }        for(int i=1;i<=m;i++){            printf("%d\n",ans[i]);        }    }    return 0;}


0 0