UPCOJ-5531 [COCI 2017-2018-2] - Garage

garage (4s256M)

More recently, Slavko has been working on sequences of natural numbers. He found that a sequence is interesting if the greatest common divisor of all elements in the sequence is greater than 1 .

Yesterday, he found a sequence of N natural numbers in his garage . Since he was bored, he decided to keep his attention by simply asking questions. Each query can be one of two types:

  1. Change the value at the X position to V
  2. Count the number of interesting subsequences in the L to R interval.

enter:

The first line has two numbers N and Q  (1 ≤ ​N, ​Q ≤ 10 ​ 5​ ), which represent the number of elements in the sequence and the number of operations.

The next line contains N numbers, representing the original number sequence. The i -th number is represented by Ai (1 ≤ ​Ai ≤ 10 9​ )

Next Q lines, each line represents an operation.

The first numeric value of the operation is 1 or 2 , indicating the type of operation.

For Type 1 , the next two numbers X and V. X (1 ≤ ​X ≤ ​N) and ​V (1 ≤ ​V ≤ 10​ 9 ​ )

For type 2 , the last two numbers L and R. (1 ≤ ​L ≤ ​R ≤ ​N)

output:

For each type 2 , output a line with a number representing the number of consecutive interesting subsequences in the given interval.

SAMPLE​​ ​​TESTS

input

5​ ​1

8​ ​4​ ​3​ ​9​ ​1

2​ ​2​ ​5

Output

4

Example 1 , the elements of interval 2 , 5 are (4, 3, 9, 1). The consecutive interesting subsequences are:

[4]​ ​3​ ​9​ ​1,4​ ​​[3]​​ ​​​​9​ ​1, 4​ ​3​ ​​[9]​ ​1, 4​ ​​[ 3, 9]​ ​1  The brackets are consecutive subsequences.

 


 

 

Topic meaning:

Given a sequence, find how many subsequences between l and r have gcd>1, support modification

 


 

 

analyze:

Thinking of divide and conquer, and the possibility of line segment tree maintenance, the difficulty now is how to merge two subsequences

 


 

 

solve:

We consider the number of answers in the maintenance interval of the direct line segment tree. The answer in the interval l+r is the answer for l plus the answer for r plus the number of strings that go from the left interval to the right interval.
We consider how to maintain the number of answers across intervals.
A substring contributes to the answer if and only if the GCD of the string is greater than 1. The problem is to maintain the number of strings whose GCD across intervals is greater than 1. The
segment tree cannot maintain data across intervals. For this kind of thing, we can split it into the form of prefix + suffix.
Record the prefix GCD and suffix GCD of each interval, and find out by
typing or thinking that the GCD of the two numbers does not exceed 1/2 of the maximum number, and the prefix GCD decreases monotonically.
Therefore, the types of prefix GCDs do not exceed log, and we can open pairs to record the value and number of prefix GCDs.
The part of the prefix GCD of the entire interval whose length does not exceed the L interval is directly inherited.
The part that exceeds L is the GCD of the entire interval of L and the GCD of the GCD of the prefix in R.
If the prefix GCD is the same, the direct number is added to the previous one.
If the prefix GCD is different, create a new pair with the value of the calculated GCD. The number is the number of GCDs of the R interval prefix.
The suffix GCD is the same.

 

Then we enumerate the suffix of the L interval and the prefix of the R interval when we get the answer of the combined interval calculation. We found that when the pointer of the L range is moved to the right, the GCD of a number is actually removed, so the pointer of the R range will also move to the right or not move. Therefore, the pointers of the LR interval are monotonically shifted to the right during the calculation.
So you can get the answer quickly with two-pointer.

 

Then pay attention to the details of the code when merging intervals. . Be sure to match. .

 

The main thing is to maintain the suffix and suffix of the
line segment tree to maintain cross-interval information. Observe the properties of GCD and find that there are only log types of different GCD two-pointers to get the answer quickly.
Go to: https://blog.csdn.net/qq_40512553/article/details/79986904
(someone I wrote it, I will not write it)

 


Attached code:

 

#include<bits/stdc++.h>
using namespace std;
const long long maxn=1e5+12;
typedef pair<int,int> par;

inline int gcd(int a,int b){if(a < b)swap(a,b);while(b){a %= b;swap(a,b);}return a;}
inline int read()
{
    int x = 0;char i = getchar();
    while(!isdigit(i))i = getchar();
    while(isdigit(i))x = x * 10 + i - '0',i = getchar();
    return x;
}
struct Tree
{
    vector<par> pre,sub;
    long long iting;
}tree[maxn<<2];
int N,Q;
inline Tree pushup(Tree l,Tree r)
{
    Tree a;a.pre.clear();a.sub.clear();
    a.pre = l.pre;a.sub = r.sub;
    for(int i = 0;i < r.pre.size();i++)
    {
      int tmp = gcd(r.pre[i].first,l.pre[l.pre.size() - 1].first);
      if(tmp == a.pre[a.pre.size() - 1].first)a.pre[a.pre.size() - 1].second += r.pre[i].second;
      else a.pre.push_back(make_pair(tmp,r.pre[i].second));
    }
    for(int i = 0;i < l.sub.size();i++)
    {
        int tmp = gcd(l.sub[i].first,r.sub[r.sub.size() - 1].first);
        if(tmp == a.sub[a.sub.size() - 1].first)a.sub[a.sub.size() - 1].second += l.sub[i].second;
        else a.sub.push_back(make_pair(tmp,l.sub[i].second));
    }
    a.iting = l.iting+ r.iting;
    int lc = l.sub.size() - 1,rc = 0;long long ls,rs = 0;bool f = 0;
    while(true)
    {
        int tmp = f ? rc - 1 : rc;
        while(lc>0&& gcd(l.sub[lc].first,r.pre[tmp].first) == 1)lc--,f = 0;
        if(lc < 0)break;if(f)lc--;
        ls = l.sub[lc].second;rs;
        while(rc < r.pre.size() && gcd(l.sub[lc].first,r.pre[rc].first) != 1)
        rs += r.pre[rc].second,rc++;
        if(gcd(l.sub[lc].first,r.pre[rc - 1].first) != 1)a.iting += ls * rs;
        if(lc <= 0)break;
        f = 1;
    }
    return a;
}
int a[maxn];
inline void build(int l,int r,int rt)
{
    if(l == r)
    {
      tree[rt].pre.clear();tree[rt].sub.clear();
      tree[rt].sub.push_back(make_pair(a[l],1));
      tree[rt].pre.push_back(make_pair(a[l],1));
      tree[rt].iting = a[l] != 1;
      return;
    }
    int mid = l + r >> 1;
    build(l,mid,rt << 1);
    build(mid + 1,r,rt << 1 | 1);
    tree[rt] = pushup(tree[rt << 1],tree[rt << 1 | 1]);
}
inline void updata(int L,int l,int r,int rt)
{
    if(l == r)
    {
      tree[rt].pre.clear();tree[rt].sub.clear();
      tree[rt].sub.push_back(make_pair(a[l],1));
      tree[rt].pre.push_back(make_pair(a[l],1));
      tree[rt].iting = a[l] != 1;
      return;
    }
    int mid = l + r >> 1;
    if(L <= mid)updata(L,l,mid,rt << 1);
    else updata(L,mid + 1,r,rt << 1 | 1);
    tree[rt] = pushup(tree[rt << 1],tree[rt << 1 | 1]);
}
inline Tree query(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R)return tree[rt];
    int mid = l + r >> 1;
    if(L > mid)return query(L,R,mid + 1,r,rt << 1 | 1);
    if(R <= mid)return query(L,R,l,mid,rt << 1);
    return pushup(query(L,R,l,mid,rt << 1),query(L,R,mid + 1,r,rt << 1 | 1));
}

int main()
{
    freopen("garaza.in","r",stdin);
    freopen("garaza.out","w",stdout);
    N=read();Q=read();
    for(int i=1;i<=N;i++) a[i]=read();
    
    build(1,N,1);
    int type,l,r;
    for(int i=1;i<=Q;i++)
    {
        type=read();l=read();r=read();
        if(type==1) a[l]=r,updata(l,1,N,1);
        else printf("%lld\n",query(l,r,1,N,1).iting);
    }
    fclose(stdin);
    fclose(stdout);
}
View Code

 

 

 


 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325280385&siteId=291194637