### 關於用線段樹去紀錄區間的一個問題

codeforces contest671的C題。

`#include<bits/stdc++.h>//對函數f(i,j):left。right表示的是i的取值范圍。此時j的取值為1-k，其中k>=minn[n]&&k<=maxn[n]，且k(minn)=minn[n],k(maxn)=maxn[n]typedef long long ll;using namespace std;ll tree[200010<<2];int minn[200010<<2];int maxn[200010<<2];int add[200010<<2];void pushDown(int temp,int left,int mid,int right,int temps){    tree[temp<<1]=1LL*temps*(mid-left+1);    tree[temp<<1|1]=1LL*temps*(right-mid);    add[temp<<1]=temps;    add[temp<<1|1]=temps;    maxn[temp<<1]=maxn[temp<<1|1]=minn[temp<<1]=minn[temp<<1|1]=temps;    add[temp]=0;}void ad(int i,int j,int temp,int left,int right,int n){    if(temp<=minn[n])        return;    if(left>=i&&right<=j&&temp>=maxn[n])    {        tree[n]=1LL*(right-left+1)*temp;        add[n]=maxn[n]=minn[n]=temp;        return;    }    int mid=(left+right)/2;    if(add[n])        pushDown(n,left,mid,right,add[n]);    if(j<=mid)        ad(i,j,temp,left,mid,n<<1);    else if(i>mid)        ad(i,j,temp,mid+1,right,n<<1|1);    else    {        ad(i,mid,temp,left,mid,n<<1);        ad(mid+1,j,temp,mid+1,right,n<<1|1);    }    tree[n]=tree[n<<1]+tree[n<<1|1];    maxn[n]=max(maxn[n<<1],maxn[n<<1|1]);    minn[n]=min(minn[n<<1],minn[n<<1|1]);}vector<int>v;int l[200010][2],r[200010][2];ll ans[200010];void deel(int pos,int val){    if(l[val][0]>pos||l[val][0]==0)    {        l[val][1]=l[val][0];        l[val][0]=pos;    }    else if(l[val][1]>pos||l[val][1]==0)        l[val][1]=pos;    if(r[val][0]<pos)    {        r[val][1]=r[val][0];        r[val][0]=pos;    }    else if(r[val][1]<pos)        r[val][1]=pos;}int main(){    int n;    cin>>n;    int val;    for(int i=1; i<=n; i++)    {        scanf("%d",&val);        for(int j=1; j*j<=val; j++)        {            if(val%j==0)            {                deel(i,j);                if(j*j!=val)                    deel(i,val/j);            }        }    }    for(int i=1; i<=n; i++)        ad(i,i,i-1,1,n,1);    for(int i=200001; i>0; i--)    {        if(l[i][0]!=r[i][0])        {            ad(1,l[i][0],r[i][1]-1,1,n,1);//當i在1-l[i][0]之間是，j必須小於等於r[i][1]-1才能保證把所有結果等於i的區間都包含進去了            ad(l[i][0]+1,l[i][1],r[i][0]-1,1,n,1);//同理            if(l[i][1]!=n)                ad(l[i][1]+1,n,n,1,n,1);//同理,此時有可能l[i][1]==n        }        //此時線段樹中存儲的是使結果大於等於i的區間數目        ans[i]=1LL*n*n-tree[1];//所以ans[i]存儲的是結果小於i的區間數目    }    ll fin=0;    for(int i=1;i<=200000;i++)        fin+=(ans[i+1]-ans[i])*i;    printf("%I64d\n",fin);    return 0;}`