您的位置:首页 > 其它

HDU5930 gcd (线段树 + 二分)

2016-10-15 10:40 681 查看
转发:http://blog.csdn.net/snowy_smile/article/details/52757953

GCD

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 78    Accepted Submission(s): 11


Problem Description

Mr. Frog likes generating numbers! He can generate many numbers from a sequence.

For a given sequence a1,a2,⋯,an Mr.
Frog can choose two numbers l and r (1≤l≤r≤n)
and calculate the gcd between l-th and r-th number in this sequence g
4000
=gcd(al,al+1,⋯,ar).
Asan expert in generating numbers, Mr. Frog wants to know how many distinct numbers can be generated by a sequence.

Mr. Frog likes challenges, so there may be many modifications in this sequence. In the i-th modification, Mr. Frog may change ap to vi.
After each modification, you are asked to tell how many distinct numbers can be generated by this sequence immediately!

 

Input

The first line contains only one integer T, which indicates the number of test cases.

For each test case, the first line includes two numbers n, q(1≤n,q≤50000).
which indicate the length of sequence and the number of modifications.

The second line contains n numbers:a1,a2,⋯,an.

Then q lines, each line contain two numbers, pi,vi(1≤pi≤n,1≤vi≤1000000).

Test data guarantee that 1<≤ai≤1000000 all
the time and the sum of all n and q is less than or equal to 2×105.

 

Output

For each test case, first output one line "Case #x:", where x is the case number (starting from 1). Then q lines, each line contain only one number, which is the answer to current sequence.

 

Sample Input

2
3 2
1 2 3
1 3
2 3

3 2
3 3 3
1 1
2 2

 

Sample Output

Case #1:
3
1
Case #2:
2
3
Hint
For case 1, after the first operation, 3,2,1 can be generated by the sequence 3, 2, 3. Whereas after the second operation, sequence 3, 3, 3 can generate only 3.

 

Source

2016CCPC东北地区大学生程序设计竞赛
- 重现赛

[cpp] view
plain copy

 print?





#include<stdio.h>  

#include<iostream>  

#include<string.h>  

#include<string>  

#include<ctype.h>  

#include<math.h>  

#include<set>  

#include<map>  

#include<vector>  

#include<queue>  

#include<bitset>  

#include<algorithm>  

#include<time.h>  

using namespace std;  

void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }  

#define MS(x,y) memset(x,y,sizeof(x))  

#define rt 1, 1, n  

#define ls o<<1  

#define rs o<<1|1  

#define lson o<<1,l,mid  

#define rson o<<1|1,mid+1,r  

typedef long long LL;  

typedef unsigned long long UL;  

typedef unsigned int UI;  

template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }  

template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }  

const int N = 5e4 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;  

template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }  

int casenum, casei;  

int n, m;  

int a[1 << 17];   //a[i]维护线段树第i个节点的区间gcd值  

int b
;       //b[i]维护第i个位置的数值  

int gcd(int x, int y)  

{  

    return y == 0 ? x : gcd(y, x%y);  

}  

void pushup(int o)  

{  

    a[o] = gcd(a[ls], a[rs]);  

}  

void build(int o, int l, int r)  

{  

    if (l == r)  

    {  

        a[o] = b[l];  

        return;  

    }  

    int mid = (l + r) >> 1;  

    build(lson);  

    build(rson);  

    pushup(o);  

}  

int P, V;  

void modify(int o, int l, int r)  

{  

    if (l == r)  

    {  

        a[o] = V;  

        return;  

    }  

    int mid = (l + r) >> 1;  

    P <= mid ? modify(lson) : modify(rson);  

    pushup(o);  

}  

int L, R, G, TP;  

int query(int o, int l, int r)  

{  

    if (l >= L && r <= R && a[o] % G == 0)return 0;  

    if (l == r)return l;  

    int mid = (l + r) >> 1;  

    int tmp = 0;  

    if (TP == 0)  

    {  

        if (R > mid)tmp = query(rson);  

        if (tmp)return tmp;  

        if (L <= mid)return query(lson);  

    }  

    else  

    {  

        if (L <= mid)tmp = query(lson);  

        if (tmp)return tmp;  

        if (R > mid)return query(rson);  

    }  

    return tmp;  

}  

vector< pair<int, int> >lft, rgt;  

LL cnt[1000010];int ans;  

int dfn[1000010]; int tim;  

void cal(int P, int sig, bool init = 0)  

{  

    lft.clear();  

    rgt.clear();  

    int i, p;  

    //get lft  

    TP = 0; p = P;  

    for (i = p, G = b[p]; i >= 1; i = p, G = gcd(G, b[p]))  

    {  

        L = 1; R = i;  

        p = query(rt);  

        lft.push_back({ i - p, G });  

    }  

    //get rgt  

    if (!init)  

    {  

        TP = 1; p = P;  

        for (i = p, G = b[p]; i <= n; i = p, G = gcd(G, b[p]))  

        {  

            L = i; R = n;  

            p = query(rt); if (p == 0) p = n + 1;  

            rgt.push_back({ p - i, G });  

        }  

    }  

    else rgt.push_back({ 1, b[p] });  

    for (auto l : lft)  

    {  

        for (auto r : rgt)  

        {  

            LL num = (LL)l.first * r.first;  

            int g = gcd(l.second, r.second);  

            if (dfn[g] != tim)dfn[g] = tim, cnt[g] = 0;  

            if (cnt[g] == 0)++ans;  

            cnt[g] += num * sig;  

            if (cnt[g] == 0)--ans;  

        }  

    }  

}  

void init()  

{  

    for (int i = 1; i <= n; ++i)cal(i, 1, 1);  

}  

int main()  

{  

    scanf("%d", &casenum);  

    for (casei = 1; casei <= casenum; ++casei)  

    {  

        scanf("%d%d", &n, &m);  

        for (int i = 1; i <= n; ++i)scanf("%d", &b[i]);  

        build(rt);  
104ab

        ++tim;   

        ans = 0;  

        init();   

        printf("Case #%d:\n", casei);  

        for (int i = 1; i <= m; ++i)  

        {  

            scanf("%d%d", &P, &V);  

            cal(P, -1);  

            b[P] = V;  

            modify(rt);  

            cal(P, 1);  

            printf("%d\n", ans);  

        }  

    }  

    return 0;  

}  

/* 

【题意】 

有n(50000)个数a[](1e6范围)和q(50000)个操作 

对于每个操作,我们会修改a[p]为v 

问你每次修改之后会剩下多少个不同的区间连续gcd 

 

【类型】 

数据结构 

 

【分析】 

一个点的gcd值会影响所有包含其的区间 

我们先预处理出n(n+1)个区间的gcd值,用一个cnt数组完成计数 

然后对于修改,我们查询出包含这个点的所有区间段(这个可以通过在线段树上二分实现),在cnt数组中消除即可 

然后再修改,再在cnt数组中加回去完成计数即可 

复杂度的瓶颈在于我们合并区间时的左log个gcd区间和右log的gcd区间再求gcd导致的(log)^3 

 

【时间复杂度&&优化】 

O(nlognlognlogn) 

 

【数据】 

input 



3 2 

1 2 3 

1 3 

2 3 

ans 

3 1 

 

input  

3 2 

3 3 3 

1 1 

2 2 

ans 

2 3 

*/  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: