ACWING246. Maximum Common Number of Intervals (Line Tree Difference)

Given a sequence A with a length of N and M instructions, each instruction may be one of the following two:

1. "C l r d" means "A[l],A[l+1],... A[r] adds D.

2. "Q l r" means to ask A[l],A[l+1],... The greatest common divisor of A[r] (GCD).

For each query, an integer is output to represent the answer.

Input format
The first row contains two integers, N and M.

The second line contains N integers A[i].

Next, M lines represent M instructions, each in the format shown in the title description.

Output format
For each query, an integer is output to represent the answer.

Each answer takes one line.

Data range
N≤500000,M≤100000
Input sample:
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4
Output sample:
1
2
4

Train of thought:

  1. By rolling phase division, gcd(x,y) = gcd(x,y - x) can be obtained. Similarly, gcd(x,y,z) = gcd(x,y - x,z - y). Then in gcd, except for the first number, other numbers can be replaced by the difference between the latter number and the former number (negative number plus abs). Thus, we use segment tree to maintain the GCD of a differential sequence.
  2. The interval updating is very natural, and the X and y+1 points can be upgraded at a single point according to the nature of the difference. But when the gcd of interval (x,y) is calculated, the latter number can be directly calculated by line segment tree. But for the first number, because it is a[i] - a[i - 1], and after many interval updates a[i] can no longer represent the point of I. But we can open an additional tree array (line segment tree) to maintain the change of difference sequence, so sum[i] + a[i] is the value represented by the point I.
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn = 500000 + 7;
ll a[maxn];
struct T
{
    ll l,r,dat;
}t[maxn << 2];
ll c[maxn],b[maxn];

ll gcd(ll n,ll m)
{
    return m == 0 ? n : gcd(m,n % m);
}

ll n,m;
void pushup(ll i)
{
    t[i].dat = gcd(t[i * 2].dat,t[i * 2 + 1].dat);
}

void build(ll i,ll l,ll r)
{
    t[i].l = l;t[i].r = r;
    if(l == r)
    {
        t[i].dat = b[l];
        return;
    }
    ll m = (l + r) >> 1;
    build(i * 2,l,m);
    build(i * 2 + 1,m + 1,r);
    pushup(i);
}

void update(ll i,ll x,ll v)
{
    if(t[i].l == t[i].r)
    {
        t[i].dat += v;
        return;
    }
    ll m = (t[i].l + t[i].r) >> 1;
    if(x <= m)
        update(i * 2,x,v);
    if(x > m)
        update(i * 2 + 1,x,v);
    pushup(i);
}

ll query(ll i,ll x,ll y)
{
    if(x <= t[i].l && t[i].r <= y)
    {
        return abs(t[i].dat);
    }
    ll m = (t[i].l + t[i].r) >> 1;
    ll res = 0;
    if(x <= m)
        res = gcd(res,query(i * 2,x,y));
    if(y > m)
        res = gcd(res,query(i * 2 + 1,x,y));
    return res;
}

ll sum(ll x)
{
    ll res = 0;
    while(x)
    {
        res += c[x];
        x -= x & (-x);
    }
    return res;
}

void add(ll x,ll v)
{
    while(x <= maxn)
    {
        c[x] += v;
        x += x & (-x);
    }
}

int main()
{
    ll n,m;scanf("%lld%lld",&n,&m);
    for(ll i = 1;i <= n;i++)
        scanf("%lld",&a[i]);
    for(ll i = 1;i <= n;i++)
        b[i] = a[i] - a[i - 1];
    build(1,1,n);
    while(m--)
    {
        char op[2];
        ll x,y;
        scanf("%s%lld%lld",op,&x,&y);
        if(op[0] == 'Q')
        {
            if(x > y)
                printf("0\n");
            else
            {
                ll al = sum(x) + a[x];
                printf("%lld\n",gcd(al,query(1,x + 1,y)));
            }
        }
        else
        {
            ll v;scanf("%lld",&v);
            update(1,x,v);
            add(x,v);
            if(y < n)
            {
                update(1,y + 1,-v);
                add(y + 1,-v);
            }
        }
    }
    return 0;
}

Posted by Sorthy359 on Wed, 02 Oct 2019 00:29:42 -0700