zoj3800線段樹+離線

You are given a sequence {A0, A1, …, AN-1} and an integer set called GS. Defined a function called G(L, R) on A, where G(L, R) = GCD(Ai) (L ≤ i < R) that is the greatest common divisor of all the integers in the subsequence {AL, AL+1, …, AR-1}.

Now There’re several questions for you. Give you three integers L, R and g, where g is an integer in GS. You need to calculate how many integer pairs (l, r) satisfy the condition that G(l, r) = g and L ≤ l < r ≤ R.

Input
Input will consist of multiple test cases. The first line of each case contains three integers N, M, Q (1≤ N, Q≤ 100000, 1 ≤ M ≤ 50), separated by spaces. The second line contains N integers, A0, A1, …, AN-1 (1≤ Ai≤ 100000). The third line contains M integers, indicating the set GS. Every integer in GS is positive and less than 2000. For the next Q line, each line contains three integers, L, R, g (0≤ L< R≤ N, g∈ GS).

Output
For each case, output Q lines. Each line contains an integer, indicating the answer for the query.

Sample Input
4 4 4
1 2 3 4
1 2 3 4
0 4 1
0 4 2
0 4 3
0 4 4
Sample Output
7
1
1
1

思路:
我們可以分析,每一次查詢的要素有三個分別是區間左端點、右端點和公因子。
1,由於集合中只有最多50個要查詢的公因子,所以可以按照公因子的值分別建立線段樹進行查詢,這樣就解決了公因子;
2,對於每一次查詢我們可以固定右端點,將每一次查詢放到對應的右端點上去,然後從左往右依次求公因子,更新公因子對應的線段樹的值,至於查詢我們是固定了右端點的,所以後面的數並不會影響結果,也就是現在就可以查詢區間右端點和目前考慮到的右端點相同的區間了。這樣就解決了區間端點問題;
3,從左往右由於考慮的數越來越多,求得的公因子的值肯定是非遞增的(當出現一個新的端點時候,可能會出現一個新的公因子,也就是新出現的數本身),其中還可能會有重複的值,這樣就可以去重減小複雜度了;

#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=100005;
int n,m,q,a[maxn],gs[53],rev[maxn];
long long ans[maxn];
struct node
{
    int L,g,i;
    node(int a=0,int b=0,int c=0)
    {
        L=a,g=b,i=c;
    }
};
vector<node> que[maxn];
struct segtree
{
    int add[maxn<<2];
    long long sum[maxn<<2];
    void build(int l,int r,int rt)
    {
        add[rt]=0;
        sum[rt]=0;
        if(l==r) return;
        int m=l+r>>1;
        build(lson);
        build(rson);
    }
    void pushUp(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void pushDown(int rt,int l,int r)
    {
        if(add[rt])
        {
            int m=l+r>>1;
            sum[rt<<1]+=(long long)add[rt]*(m-l+1);
            sum[rt<<1|1]+=(long long)add[rt]*(r-m);
            add[rt<<1]+=add[rt];
            add[rt<<1|1]+=add[rt];
            add[rt]=0;
        }
    }
    void update(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            add[rt]++;
            sum[rt]+=(r-l+1);
            return;
        }
        int m=l+r>>1;
        pushDown(rt,l,r);
        if(L<=m)
            update(L,R,lson);
        if(m<R)
            update(L,R,rson);
        pushUp(rt);
    }
    long long query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
            return sum[rt];
        pushDown(rt,l,r);
        int m=l+r>>1;
        long long ans=0;
        if(L<=m) ans+=query(L,R,lson);
        if(m<R) ans+=query(L,R,rson);
        return ans;
    }
} tree[51];
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
void solve()
{
    int tot=0;
    pair<int,int> sp[maxn];
    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<tot; j++)
        {
            int tmp=gcd(sp[j].first,a[i]);
            sp[j].first=tmp;
        }
        if(tot>0&&a[i]==sp[tot-1].first)
            sp[tot-1].second++;
        else
            sp[tot++]=make_pair(a[i],1);
        if(tot)
        {
            int tmp=1;
            for(int j=1; j<tot; j++)
            {
                if(sp[j].first==sp[tmp-1].first)
                    sp[tmp-1].second+=sp[j].second;
                else
                    sp[tmp++]=sp[j];
            }
            tot=tmp;
        }

        int cnt=0,L,R,tmp,pos;
        for(int j=0; j<tot; j++)
        {
          tmp=sp[j].first;
          pos=rev[tmp];
          if(pos!=-1)
          {
              L=cnt+1;
              R=cnt+sp[j].second;
              tree[pos].update(L,R,1,n,1);
          }
          cnt+=sp[j].second;
        }
        for(int j=0; j<que[i].size(); j++)
        {
            node tt=que[i][j];
            ans[tt.i]=tree[rev[tt.g]].query(tt.L,i,1,n,1);
        }
    }
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&q))
    {
        memset(rev,0xff,sizeof rev);
        for(int i=0; i<=m; i++)
            tree[i].build(1,n,1);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            que[i].clear();
        }
        for(int i=1; i<=m; i++)
        {
            scanf("%d",&gs[i]);
            rev[gs[i]]=i;
        }
        int L,R,g;
        for(int i=1; i<=q; i++)
        {
            scanf("%d%d%d",&L,&R,&g);
            L++;
            que[R].push_back(node(L,g,i));
        }
        solve();
        for(int i=1; i<=q; i++)
            printf("%lld\n",ans[i]);
    }
    return 0;
}
發佈了174 篇原創文章 · 獲贊 64 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章