CF671C Ultimate Weirdness of an Array 数论线段树

Posted itst

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF671C Ultimate Weirdness of an Array 数论线段树相关的知识,希望对你有一定的参考价值。

传送门


考虑计算(forall p in [0,200000] , sumlimits_{l} sumlimits_{r geq l} [f_{l,r} leq p]),这样我们通过差分可以得到最后的答案。

首先不难发现当固定了某个左端点(l)(p)之后,满足条件的(r)一定是原序列的一段后缀。设(r_l)表示当左端点为(l)时最小的右端点,那么(l)作为左端点对答案的贡献就是(N+1-r_l)

考虑当(p)变为(p-1)(r_x)会如何变化。这相当于去掉满足(f_{l,r} = p)的区间,而这又等价于不能让当前区间之外的部分出现至少(2)(p)的倍数。

把所有(p)的倍数拿出来形成一个序列(x_1,x_2,...,x_k),如果(k leq 1)显然不会做操作,否则区间([l,r])内至少要包含序列中的至少(k-1)个位置。也就是说:

1、当(l > x_2)时,(r_l = N + 1),这表示已经不存在区间满足条件了;

2、当(l in (x_1,x_2])时,(r_l = max{r_l , x_m}),也就是至少要把(x_2 sim x_m)覆盖;

3、当(l in [1,x_1])时,(r_l = max{r_l , x_{m-1}}),也就是至少要把(x_1 sim x_{m-1})覆盖。

所以我们需要一个数据结构支持区间(max)和区间和。似乎要写jiry树,但是因为(r_l)一定是单调不降的,所以在给定覆盖区间和取(max)的值之后被修改的区间一定是一段前缀,于是这个操作就等价于区间赋值了。这个就可以比较优美地实现。

#include<bits/stdc++.h>
using namespace std;

int read(){
    int a = 0; char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)){a = a * 10 + c - 48; c = getchar();}
    return a;
}

#define int long long
const int _ = 2e5 + 7 , M = 2e5;
namespace segt{
    int sum[_ << 2] , mrk[_ << 2] , mx[_ << 2] , mn[_ << 2] , sz[_ << 2];

#define mid ((l + r) >> 1)
#define lch (x << 1)
#define rch (x << 1 | 1)
    
    void mark(int x , int val){mrk[x] = mx[x] = mn[x] = val; sum[x] = sz[x] * val;}
    void down(int x){if(mrk[x]){mark(lch , mrk[x]); mark(rch , mrk[x]); mrk[x] = 0;}}
    void up(int x){sum[x] = sum[lch] + sum[rch]; mx[x] = mx[rch]; mn[x] = mn[lch];}
    
    void init(int x , int l , int r){
        sz[x] = r - l + 1;
        if(l == r) sum[x] = mx[x] = mn[x] = l; else{init(lch , l , mid); init(rch , mid + 1 , r); up(x);}
    }

    void mdy(int x , int l , int r , int L , int R , int val){
        if(L > R || mn[x] >= val) return;
        if(l >= L && r <= R && mx[x] <= val) return mark(x , val);
        down(x);
        if(mid >= L) mdy(lch , l , mid , L , R , val);
        if(mid < R) mdy(rch , mid + 1 , r , L , R , val);
        up(x);
    }
}using namespace segt;
int N , arr[_] , ans[_]; vector < int > ys[_] , pos[_];

signed main() {
    N = read();
    for(int i = 1 ; i <= M ; ++i)
        for(int j = 1 ; j * i <= M ; ++j)
            ys[i * j].emplace_back(i);
    for(int i = 1 ; i <= N ; ++i){int id = read(); for(auto t : ys[id]) pos[t].emplace_back(i);}
    init(1 , 1 , N); ans[M] = (N + 1) * N - sum[1];
    for(int i = M ; i ; --i){
        if(pos[i].size() > 1){
            mdy(1 , 1 , N , pos[i][1] + 1 , N , N + 1);
            mdy(1 , 1 , N , pos[i][0] + 1 , pos[i][1] , pos[i][pos[i].size() - 1]);
            mdy(1 , 1 , N , 1 , pos[i][0] , pos[i][pos[i].size() - 2]);
        }
        ans[i - 1] = (N + 1) * N - sum[1];
    }
    int sum = 0; for(int i = 1 ; i <= M ; ++i) sum += (ans[i] - ans[i - 1]) * i;
    cout << sum; return 0;
}

以上是关于CF671C Ultimate Weirdness of an Array 数论线段树的主要内容,如果未能解决你的问题,请参考以下文章

公交车模拟器ultimate。如何下载?

IntelliJ IDEA(Ultimate版本)的下载安装和WordCount的初步使用(本地模式和集群模式)Ultimate

请问WIN7的professional和ultimate不同

win7 ultimate 和 pro有啥区别

Windows 7 版本里面的Ultimate,Professional,Home Premium

Visual Studio ultimate 2012 RC的评估期将在3天后结束,您将需要升级到最新版本?? 必须升级吗?