zoukankan      html  css  js  c++  java
  • 关于用线段树去纪录区间的一个问题

    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
    ",fin);
        return 0;
    }
  • 相关阅读:
    CF 429C
    GDOI2015滚粗记
    JLOI2015 城池攻占
    GDKOI2014 石油储备计划
    HNOI2012 射箭
    移动端复制到剪贴板
    再谈mobile web retina 下 1px 边框解决方案
    css去除chrome下select元素默认border-radius
    整理低版本ie兼容问题的解决方案
    移动端按钮交互变色实
  • 原文地址:https://www.cnblogs.com/lthb/p/5539224.html
Copyright © 2011-2022 走看看