hdu 5930(线段树二分 求区间gcd )

GCD

2016 CCPC东北赛区

思路: 我们可以用线段树在nlogn的时间内预处理出所有的不相同的gcd数以及他们出现的个数。因为连续区间的gcd gcd的大小下降的是非常快的,所以可以结合二分求,当然打出一个ST表也可以求出,但是不太适合这个题,这个题要求动态修改,还是线段树好一点,然后对于每一次修改,我可以二分处理出以他为结尾的gcd数以及他们的区间, 不会超过logn个,取决于上边的性质,当然也可以二分处理出以他为开头的所有的gcd数以及区间,这样的话,还是不够的,如果x出现在中间内,当然就可以两边for就处理出所有的由x产生影响的,gcd,然后删除,更新,再求一遍,加上。 

代码:

#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)

using namespace std;
typedef long long ll;
typedef pair<int,int > pii;
const int N =50005;
const int NUM=1e6+5;

int n,q;
int a[N];
int cnt[NUM];
int ans;
vector< pii >pre[N];
vector< pii >post[N];

struct node
{
    int l,r;
    int val;
}tr[N<<2];

void push_up(int i)
{
    tr[i].val=__gcd(tr[lson].val,tr[rson].val);
}

void build(int i,int l,int r)
{
    tr[i].l=l;
    tr[i].r=r;
    tr[i].val=0;
    if(l==r)
    {
        tr[i].val=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(i);
}

void update(int i,int aim,int val)
{
    if(tr[i].l==aim&&tr[i].r==tr[i].l)
    {
        tr[i].val=val;
        return ;
    }
    int mid=(tr[i].l+tr[i].r)>>1;
    if(aim<=mid) update(lson,aim,val);
    else update(rson,aim,val);
    push_up(i);
}

int querypre(int i,int l,int r,int now,int &gcd)
{
    int L=tr[i].l;
    int R=tr[i].r;
    int gg=tr[i].val;
    if(l<=L&&r>=R)
    {
        if(__gcd(gcd,gg)<now)
        {
            if(L==R) return L;
            else
            {
                int mid=(L+R)>>1;
                int ls=0,rs=0;
                rs=querypre(rson,l,r,now,gcd);
                if(rs) return rs;
                ls=querypre(lson,l,r,now,gcd);
                return ls;
            }
        }
        else
        {
            gcd=__gcd(gcd,gg);
            return 0;
        }
    }
    int mid=(L+R)>>1;
    int ls=0,rs=0;
    if(r>mid)rs=querypre(rson,l,r,now,gcd);
    if(rs) return rs;
    if(l<=mid)ls=querypre(lson,l,r,now,gcd);
    return ls;
}

int querypost(int i,int l,int r,int now,int &gcd)
{
    int L=tr[i].l;
    int R=tr[i].r;
    int gg=tr[i].val;
    if(l<=L&&r>=R)
    {
        if(__gcd(gg,gcd)<now)
        {
            if(L==R) return L;
            else
            {
                int mid=(L+R)>>1;
                int ls=0,rs=0;
                ls=querypost(lson,l,r,now,gcd);
                if(ls) return ls;
                rs=querypost(rson,l,r,now,gcd);
                return rs;
            }
        }
        else
        {
            gcd=__gcd(gcd,gg);
            return 0;
        }
    }
    int mid=(L+R)>>1;
    int ls=0,rs=0;
    if(l<=mid) ls=querypost(lson,l,r,now,gcd);
    if(ls) return ls;
    if(r>mid) rs=querypost(rson,l,r,now,gcd);
    return rs;
}


vector< pii >ppre;
vector< pii >ppost;

void solve(int id,int op)
{
    ppre.clear();
    ppost.clear();
    if(op==0)
    {
        //cout<<"lalal"<<endl;
        int now=a[id];
        int p=id;
        while(p>=1)
        {
            int gcd=a[id];
            int pos=querypre(1,1,id,now,gcd);
            int len=p-pos;
            ppre.push_back(pii(now,len));
            p=pos;
            if(p>=1) now=__gcd(now,a[p]);
        }
        //cout<<"eeee "<<endl;
        now=a[id];
        p=id;
        while(p<=n)
        {
            int gcd=a[id];
            //cout<<"yyyyyyyyyyyy"<<endl;
            int pos=querypost(1,id,n,now,gcd);
            //cout<<"uuauaua"<<endl;
            if(pos==0) pos=n+1;
            int len=pos-p;
            ppost.push_back(pii(now,len));
            p=pos;
            if(p<=n) now=__gcd(now,a[p]);
        }
        //cout<<"eeee "<<endl;

        for(int i=0; i<ppre.size(); i++)
        {
            for(int j=0; j<ppost.size(); j++)
            {
                int num1,num2,len1,len2;
                num1=ppre[i].first;
                num2=ppost[j].first;
                len1=ppre[i].second;
                len2=ppost[j].second;
                int gcd=__gcd(num1,num2);
                cnt[gcd]-=len1*len2;
                if(cnt[gcd]==0)
                {
                    ans--;
                }
            }
        }
    }
    else
    {
        //cout<<"aaaaaaaaaaaaaaaaaaaaaaaaa"<<endl;
        int now=a[id];
        int p=id;
        while(p>=1)
        {
            int gcd=a[id];
            int pos=querypre(1,1,id,now,gcd);
            int len=p-pos;
            ppre.push_back(pii(now,len));
            p=pos;
            if(p>=1) now=__gcd(now,a[p]);
        }
        //cout<<"eeee "<<endl;
        now=a[id];
        p=id;
        while(p<=n)
        {
            int gcd=a[id];
            //cout<<"yyyyyyyyyyyy"<<endl;
            int pos=querypost(1,id,n,now,gcd);
            //cout<<"uuauaua"<<endl;
            if(pos==0) pos=n+1;
            int len=pos-p;
            ppost.push_back(pii(now,len));
            p=pos;
            if(p<=n) now=__gcd(now,a[p]);
        }
        //cout<<"eeee "<<endl;

        for(int i=0; i<ppre.size(); i++)
        {
            for(int j=0; j<ppost.size(); j++)
            {
                int num1,num2,len1,len2;
                num1=ppre[i].first;
                num2=ppost[j].first;
                len1=ppre[i].second;
                len2=ppost[j].second;
                int gcd=__gcd(num1,num2);
                if(cnt[gcd]==0) ans++;
                cnt[gcd]+=len1*len2;
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    int kk=0;
    while(T--)
    {
        ans=0;
        memset(cnt,0,sizeof(cnt));

        scanf("%d %d",&n,&q);
        for(int i=1; i<=n; i++) scanf("%d",&a[i]);
        build(1,1,n);
        for(int i=1; i<=n; i++)
        {
            //cout<<"***** i "<<i<<endl;
            int p=i;
            int now=a[i];
            while(p>=1)
            {
                int gcd=a[i];
                int pos=querypre(1,1,i,now,gcd);
                cnt[now]+=p-pos;
                //cout<<"now "<<now<<" l "<<pos<<" r "<<p<<endl;
                p=pos;
                if(p>=1) now=__gcd(now,a[p]);
            }
        }
        for(int i=1;i<NUM;i++) if(cnt[i]) ans++;

        //cout<<"ans "<<ans<<endl;

        printf("Case #%d:\n",++kk);
        int id,val;
        while(q--)
        {
            scanf("%d %d",&id,&val);
            solve(id,0);
            update(1,id,val);
            a[id]=val;
            solve(id,1);
            printf("%d\n",ans);

        }

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82110811