GCD HDU - 5930

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

先预处理出整个区间有多少个gcd 统计每个gcd出现多少次

然后还有一个巧妙的地方就是 对每个把tar位置的数改为val的修改 把[1,tar]和[tar,n]这左右边各有多少gcd值不同的以tar为右左端点的区间找出并记下来 因为这些区间数量很少 所以用两层for循环处理 对于一个gcd的出现次数 如果加之前为零 总答案加加 如果减之后为零 总答案减减

和hdu5726类似 具体细节详见之前写的博客https://blog.csdn.net/sunyutian1998/article/details/78855918

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long

struct node1
{
    int l;
    int r;
    int val;
};

struct node2
{
    int gcd;
    ll len;
};

node1 tree[200010];
ll cnt[1000010];
int num[50010];
int n,q,ans;

int getgcd(int a,int b)
{
    int t;
    while(b>0)
    {
        t=b;
        b=a%b;
        a=t;
    }
    return a;
}

void pushup(int cur)
{
    tree[cur].val=getgcd(tree[2*cur].val,tree[2*cur+1].val);
}

void build(int l,int r,int cur)
{
    int m;
    tree[cur].l=l;
    tree[cur].r=r;
    if(l==r)
    {
        tree[cur].val=num[l];
        return;
    }
    m=(l+r)/2;
    build(l,m,2*cur);
    build(m+1,r,2*cur+1);
    pushup(cur);
}

int queryI(int tp,int pl,int pr,int gcd,int cur)
{
    int res;
    if(pl<=tree[cur].l&&tree[cur].r<=pr&&tree[cur].val%gcd==0) return 0;
    if(tree[cur].l==tree[cur].r) return tree[cur].l;
    res=0;
    if(!tp)
    {
        if(pr>=tree[2*cur+1].l) res=queryI(tp,pl,pr,gcd,2*cur+1);
        if(res==0&&pl<=tree[2*cur].r) res=queryI(tp,pl,pr,gcd,2*cur);
    }
    else
    {
        if(pl<=tree[2*cur].r) res=queryI(tp,pl,pr,gcd,2*cur);
        if(res==0&&pr>=tree[2*cur+1].l) res=queryI(tp,pl,pr,gcd,2*cur+1);
    }
    return res;
}

int queryII(int pl,int pr,int cur)
{
    int res;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        return tree[cur].val;
    }
    res=0;
    if(pl<=tree[2*cur].r) res=getgcd(queryII(pl,pr,2*cur),res);
    if(pr>=tree[2*cur+1].l) res=getgcd(queryII(pl,pr,2*cur+1),res);
    return res;
}

void update(int tar,int val,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        tree[cur].val=val;
        return;
    }
    if(tar<=tree[2*cur].r) update(tar,val,2*cur);
    else update(tar,val,2*cur+1);
    pushup(cur);
}

void init()
{
    int i,p,res,gcd;
    memset(cnt,0,sizeof(cnt));
    ans=0;
    for(i=1;i<=n;i++)
    {
        p=i,gcd=num[p];
        while(p<=n)
        {
            res=queryI(1,p,n,gcd,1);
            if(res==0) res=n+1;
            if(cnt[gcd]==0) ans++;
            cnt[gcd]+=(res-p);
            gcd=getgcd(gcd,num[res]);
            p=res;
        }
    }
}

void solve(int tar,int val)
{
    vector <node2> prel,prer;
    node2 tmp;
    ll len;
    int p,l,r,m,i,j,res,gcd;
    p=tar,gcd=num[tar];
    while(p>=1)
    {
        res=queryI(0,1,p,gcd,1);
        tmp.gcd=gcd,tmp.len=p-res;
        prel.push_back(tmp);
        gcd=getgcd(gcd,num[res]);
        p=res;
    }
    p=tar,gcd=num[tar];
    while(p<=n)
    {
        res=queryI(1,p,n,gcd,1);
        if(res==0) res=n+1;
        tmp.gcd=gcd,tmp.len=res-p;
        prer.push_back(tmp);
        gcd=getgcd(gcd,num[res]);
        p=res;
    }

    for(i=0;i<prel.size();i++)
    {
        for(j=0;j<prer.size();j++)
        {
            len=prel[i].len*prer[j].len;
            gcd=getgcd(prel[i].gcd,prer[j].gcd);
            if(cnt[gcd]==0) ans++;
            cnt[gcd]+=len*val;
            if(cnt[gcd]==0) ans--;
        }
    }
}

int main()
{
    int t,cas,i,tar,val;
    scanf("%d",&t);
    for(cas=1;cas<=t;cas++)
    {
        scanf("%d%d",&n,&q);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        build(1,n,1);
        init();
        printf("Case #%d:\n",cas);
        while(q--)
        {
            scanf("%d%d",&tar,&val);
            solve(tar,-1);
            update(tar,val,1);
            num[tar]=val;
            solve(tar,1);
            printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/81129484