HDU5869 Different GCD Subarray Query(线段树&&离线处理)

题目:

http://acm.split.hdu.edu.cn/showproblem.php?pid=5869

题意:

找区间内所有子串GCD的个数

思路:

线段树离线搞搞,区间GCD收敛的很快,所以直接暴力预处理出到每个数字截至的后缀串有哪些GCD以及它们的位置,就是每个数字向前看有哪些GCD出现,这个数量是很少的。扫一遍然后离线询问,对于每个询问按照右端点排序。找到每个位置的时候把这个位置向前看的所有GCD的位置更新到pos[]里,pos[]存的就是每个gcd最后出现的位置,然后对于右端点在当前位置的询问线段树找一下pos[]在这个区间内的和就是答案了。

代码:

//kopyh
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define N 112345
using namespace std;
int n,m,sum,res,flag;
#define root 1 , n , 1
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
struct node
{
    int pos,val;
    node(int x=0,int y=0){pos=x,val=y;}
    friend bool operator < (node a, node b)
    {
        return a.val < b.val;
    }
    friend node operator + (node a, node b)
    {
        return  node(a.pos,a.val+b.val);
    }
}arr[N<<2];
int add[N<<2],tot;
void pushUp(int rt)
{
    arr[rt] = arr[rt<<1]+arr[rt<<1|1];
}
void pushDown(int l,int r,int rt)
{
    if(add[rt])
    {
        int m = (l+r)>>1;
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        arr[rt<<1].val += (m-l+1)*add[rt];
        arr[rt<<1|1].val += (r-m)*add[rt];
        add[rt] = 0;
    }
}
void updata(int l,int r,int rt,int ql,int qr,int val)
{
    if(l>qr||ql>r)return;
    if(l>=ql&&r<=qr)
    {
        arr[rt].val += (r-l+1)*val;
        add[rt] += val;
        return;
    }
    pushDown(l,r,rt);
    int m = (l+r)>>1;
    if(ql<=m)updata(lson,ql,qr,val);
    if(qr>m)updata(rson,ql,qr,val);
    pushUp(rt);
}
void build(int l,int r,int rt)
{
    add[rt]=0;
    if(l == r)
    {
        arr[rt].val = 0;
        arr[rt].pos = tot;
        return;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    pushUp(rt);
}
node query(int l,int r,int rt,int ql,int qr)
{
    if(l>qr||ql>r)
        return node(0,0);
    if(l>=ql&&r<=qr)
        return arr[rt];
    pushDown(l,r,rt);
    int m = (l+r)>>1;
    return query(lson,ql,qr)+query(rson,ql,qr);
}
int a[N],pos[N*10],ans[N];
vector<pair<int,int> >vc[N],qu[N];
int gcd(int x,int y)
{   return y?gcd(y,x%y):x;  }
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("test.txt","r",stdin);
    #endif
    int i,j,k,cas,T,t,x,y,z,now;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            vc[i].clear();
            qu[i].clear();
        }
        for(i=1;i<=n;i++)
        {
            x=a[i]; y=i;
            for(j=0;j<vc[i-1].size();j++)
            {
                t = gcd(vc[i-1][j].first,a[i]);
                if(t!=x)
                {
                    vc[i].push_back(make_pair(x,y));
                    x=t; y=vc[i-1][j].second;
                }
            }
            vc[i].push_back(make_pair(x,y));
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            qu[y].push_back(make_pair(x,i));
        }
        memset(pos,0,sizeof(pos));
        build(root);
        for(i=1;i<=n;i++)
        {
            for(j=0;j<vc[i].size();j++)
                if(pos[vc[i][j].first] < vc[i][j].second)
                {
                    if(pos[vc[i][j].first])updata(root,pos[vc[i][j].first],pos[vc[i][j].first],-1);
                    updata(root,vc[i][j].second,vc[i][j].second,1);
                    pos[vc[i][j].first] = vc[i][j].second;
//                    printf("pos=%d %d\n",vc[i][j].first,pos[vc[i][j].first]);
                }
            for(j=0;j<qu[i].size();j++)
                ans[qu[i][j].second] = query(root,qu[i][j].first,i).val;
        }
        for(i=1;i<=m;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值