Codeforces 672 E:Ultimate Weirdness of an Array 线段树 ★ ★ ★

来源:互联网 发布:制作合格证的软件 编辑:程序博客网 时间:2024/06/08 06:51

题意是求所有区间[i,j],f(i,j)的和。f(i,j)表示除去i,j的区间之外的数其中两个最大的gcd。


ai是从1到200000的数,对于每一个i维护一个区间h(j,k),h(j,k)的含义是f(j,k)<=i,对于每一个j,找最小的k。

然后对于i来说的话,gcd<=i的区间数目就可以枚举j,对每一个j算相应的k值,也就是题解中的next[j]值。sum(n-next[j]+1) (1<=j<=n)

可以发现就是找能够整除这个数的最左距离,次左距离,次右距离,最右距离。

之后就是使用线段树更新这个和了。

#include <set>#include <map>#include <stack>#include <queue>#include <deque>#include <cmath>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define L(i) i<<1#define R(i) i<<1|1#define INF  0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-9#define maxn 200010#define MOD 1000000007typedef long long LL;struct node{    int l,r;    int Min,Max,lazy;    long long sum;} tree[maxn*4];int n,a[maxn],idx[maxn];int l1[maxn],l2[maxn],r1[maxn],r2[maxn];long long tmp[maxn];void pushup(int pos){    tree[pos].Max = max(tree[pos<<1].Max,tree[pos<<1|1].Max);    tree[pos].Min = min(tree[pos<<1].Min,tree[pos<<1|1].Min);    tree[pos].sum = tree[pos<<1].sum + tree[pos<<1|1].sum;}void pushdown(int pos){    if(!tree[pos].lazy)        return;    tree[pos<<1].Max = tree[pos<<1|1].Max = tree[pos].lazy;    tree[pos<<1].Min = tree[pos<<1|1].Min = tree[pos].lazy;    tree[pos<<1].lazy = tree[pos<<1|1].lazy = tree[pos].lazy;    tree[pos<<1].sum = (long long)(tree[pos<<1].r - tree[pos<<1].l+1) * tree[pos].lazy;    tree[pos<<1|1].sum = (long long)(tree[pos<<1|1].r-tree[pos<<1|1].l+1) * tree[pos].lazy;    tree[pos].lazy = 0;}void build(int l,int r,int pos){    tree[pos].l = l;    tree[pos].r = r;    tree[pos].lazy = 0;    if(l == r)    {        tree[pos].Max = tree[pos].Min = l;        tree[pos].sum = (long long)l;        return;    }    int mid = (l+r)/2;    build(l,mid,pos<<1);    build(mid+1,r,pos<<1|1);    pushup(pos);}                                                   //建树                                                  //查询操作void update(int l,int r,int pos,int val){    if(l > r)        return ;    if(tree[pos].Min >= val)                           //这里需要注意单独写        return;    if(tree[pos].l == l && tree[pos].r == r && tree[pos].Max <= val) //<span style="font-family:SimSun;">这里需要写在判断上,不能写在里面</span>    {        tree[pos].sum = (long long)(r-l+1) * val;        tree[pos].Max = tree[pos].Min = val;        tree[pos].lazy = val;        return ;    }    pushdown(pos);    int mid = (tree[pos].l + tree[pos].r) >> 1;    if(r <= mid)        update(l,r,pos<<1,val);    else if(l > mid)        update(l,r,pos<<1|1,val);    else    {        update(l,mid,pos<<1,val);        update(mid+1,r,pos<<1|1,val);    }    pushup(pos);}                                         //自上而下更新节点int main(){    int t;    while(scanf("%d",&n) != EOF)    {        memset(l1,0,sizeof(l1));        memset(l2,0,sizeof(l2));        memset(r1,0,sizeof(r1));        memset(r2,0,sizeof(r2));        for(int i = 1; i <= n; i++)        {            scanf("%d",&a[i]);            idx[a[i]] = i;        }        for(int i = 1; i <= maxn; i++)            for(int j = i; j <= maxn; j+=i)                if(idx[j])                {                    if(!l1[i] || l1[i] > idx[j])                    {                        l2[i] = l1[i];                        l1[i] = idx[j];                    }                    else if(!l2[i] || l2[i] > idx[j])                        l2[i] = idx[j];                    if(!r1[i] || r1[i] < idx[j])                    {                        r2[i] = r1[i];                        r1[i] = idx[j];                    }                    else if(!r2[i] || r2[i] < idx[j])                        r2[i] = idx[j];                }        build(1,n,1);        for(int i = maxn; i > 0; i--)        {            if(l1[i] != r1[i])            {                update(1,l1[i],1,r2[i]);                update(l1[i]+1,l2[i],1,r1[i]);                update(l2[i]+1,n,1,n+1);            }            tmp[i] = n*(n+1) - tree[1].sum;        }        long long ans = 0;        for(int i = 1; i < maxn; i++)            ans += (long long)i * (tmp[i+1] - tmp[i]);        printf("%lld\n",ans);    }    return 0;}


0 0