hdu 5726 (線段樹 GCD RMQ)多校第一場1004

題意:T組測試數據,每組數據給你n個數,m次詢問每次詢問包含兩個數字l,r。每次查詢[l,r]區間內的數的最大公約數。並輸出整個序列中最大公約數與[l,r]最大公約數相等的組數。

解題方法:可以通過線段樹來記錄每段區間內的最大公約數,但是後來統計與[l,r]最大公約數相等的個數時,老是超時。最後也還是在網上查的代碼。

但是後來看了也有用RMQ來解題的,後來想了想,RMQ比線段樹查詢起來可能效率更快。


附線段樹ac代碼:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <map>

using namespace std;

#define ll long long

const int maxn=1000010;

struct node{///線段樹的存儲結構
    int l,r;
    ll gcd;
}Tree[maxn<<2];

ll a[maxn];

ll gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}

void pushup(int rt)
{
    Tree[rt].gcd=gcd(Tree[rt*2].gcd,Tree[rt*2+1].gcd);
}

///建立線段樹
void Build(int l,int r,int rt)
{
    Tree[rt].l=l,Tree[rt].r=r;
    if(l==r)
    {
        Tree[rt].gcd=a[l];
        return ;
    }
    int mid=(l+r)/2;
    Build(l,mid,rt*2);
    Build(mid+1,r,rt*2+1);
    pushup(rt);
}

///詢問線段樹
ll queryans(int L,int R,int rt)
{
    if(L<=Tree[rt].l&&Tree[rt].r<=R)
    {
        return Tree[rt].gcd;
    }
    int mid=(Tree[rt].l+Tree[rt].r)/2;
    ll ans=0;
    if(L<=mid) ans=gcd(ans,queryans(L,R,rt*2));
    if(mid<R)  ans=gcd(ans,queryans(L,R,rt*2+1));
    return ans;
}
int n;
map<ll,ll>ans;
map<ll,ll>mp1;//mp1代表以x[i]結尾的所有區間的gcd的個數
map<ll,ll>mp2;//臨時變量

int main()
{
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        scanf("%d",&n);
        ans.clear();
        mp1.clear();
        mp2.clear();
        ///輸入數據
        for(int i=1; i<=n; i++) scanf("%I64d",&a[i]);

        Build(1,n,1);///建立線段樹
        mp1[a[1]]++;
        ans[a[1]]++;
        ///將查詢的ged的結果存到ans中
        for(int i=2; i<=n; i++)
        {
            ll now=a[i];
            mp2[now]++;
            ans[now]++;
            map<ll,ll>::iterator  it;
            for(it=mp1.begin(); it!=mp1.end(); it++)
            {
                int nex=gcd(now,it->first);
                ans[nex]+=it->second;
                mp2[nex]+=it->second;
            }
            mp1.clear();
            for(it=mp2.begin(); it!=mp2.end(); it++)
            {
                mp1[it->first]=it->second;
            }
            mp2.clear();
        }
        int q;
        printf("Case #%d:\n",cas++);
        scanf("%d",&q);
        ///查詢輸出過程
        while(q--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            ll temp=queryans(l,r,1);
            printf("%I64d %I64d\n",temp,ans[temp]);
        }
    }
}


另外轉載一下別的大神的RMQ代碼:


RMQ統計預處理[l,r]內的gcd值

枚舉左端點,隨着右端點增大,gcd值越來越小,二分這些變小的節點,統計出線段的gcd值所作的貢獻,map累加每個貢獻的數量

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#include<string>  
#include<vector>  
#include<ctime>  
#include<queue>  
#include<set>  
#include<map>  
#include<stack>  
#include<iomanip>  
#include<cmath>  
#define mst(ss,b) memset((ss),(b),sizeof(ss))  
#define maxn 0x3f3f3f3f  
#define MAX 1000100  
///#pragma comment(linker, "/STACK:102400000,102400000")  
typedef long long ll;  
typedef unsigned long long ull;  
#define INF (1ll<<60)-1  
using namespace std;  
ll a[100100];  
ll mp[100100][65];  
ll gcd(ll a,ll b){  
    return b==0?a:gcd(b,a%b);  
}  
int n,q;  
void RMQ_init(){  
    for(int i=1;i<=n;i++) mp[i][0]=a[i];  
    int m=log(n)/log(2);  
    for(int i=1;i<=m;i++){  
        for(int j=n;j>=1;j--){  
            mp[j][i]=mp[j][i-1];  
            if(j+(1<<(i-1))<=n)  
                mp[j][i]=gcd(mp[j][i],mp[j+(1<<(i-1))][i-1]);  
        }  
    }  
}  
int query(int l,int r){  
    int m=log(r-l+1)/log(2);  
    return gcd(mp[l][m],mp[r-(1<<m)+1][m]);  
}  
map<int,ll>V;  
int main(){  
    int T;  
    scanf("%d",&T);  
    for(int cas=1;cas<=T;cas++){  
        scanf("%d",&n);  
        V.clear();  
        for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);  
        RMQ_init();  
        for(int i=1;i<=n;i++){  
            ll tmp=a[i];  
            int l=i,r=n,mid,ans=l,O=l;  
            while(tmp>1){  
                O=l;r=n;ans=-1;  
                while(l<=r){  
                    mid=(l+r)/2;  
                    if(query(i,mid)<tmp) r=mid-1;  
                    else {  
                        l=mid+1;  
                        ans=mid;  
                    }  
                }  
                if(tmp==1) break;  
                V[tmp]+=ans-O+1;  
                l=ans+1;  
                if(l>n) break;  
                tmp=query(i,l);  
            }  
            if(tmp==1){  
                V[1]+=n-l+1;  
            }  
        }  
        scanf("%d",&q);  
        printf("Case #%d:\n",cas);  
        while(q--){  
            int l,r;  
            scanf("%d%d",&l,&r);  
            ll x=query(l,r);  
            printf("%I64d %I64d\n",x,V[x]);  
        }  
    }  
    return 0;  
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章