Continuous Intervals 线段树

题意:给出一个序列  ai

问有多少对 l r   满足 将  a[l]-a[r]之间的数sort一下   a[l]-a[r] 相邻的数字差值差值不大于1

非常巧妙的线段树   比赛的时候根本没啥头绪

对于每一个L 和都可能需要修改  那么用单调栈进行维护即可  cnt的话 用last来维护

对于那个-1  因为每次加入一个R 当L=R的那对LR 是一定满足条件的   所以最小值一定是-1   也就是最小值一定满足答案   所以这个-1也就没有意义  build的时候初始化任意值都可以 

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=1e5+10;

int minn[N<<2],t[N<<2],n,m,col[N<<2],a[N];
ll ans;
void up(int pos)
{
    if(minn[pos<<1]==minn[pos<<1|1])
    minn[pos]=minn[pos<<1],t[pos]=t[pos<<1]+t[pos<<1|1];
    else if(minn[pos<<1]<minn[pos<<1|1])
    minn[pos]=minn[pos<<1],t[pos]=t[pos<<1];
    else minn[pos]=minn[pos<<1|1],t[pos]=t[pos<<1|1];
}
void down(int pos)
{
    if(!col[pos])return;
    col[pos<<1]+=col[pos];
    col[pos<<1|1]+=col[pos];
    minn[pos<<1]+=col[pos];
    minn[pos<<1|1]+=col[pos];
    col[pos]=0;
}
void build(int l,int r,int pos)
{   
    col[pos]=0;
    if(l==r){minn[pos]=0;t[pos]=1;return ;}
    int m=(l+r)>>1;build(l,m,pos<<1);build(m+1,r,pos<<1|1);
    up(pos);
}
void UPsum(int L,int R,int v,int l,int r,int pos)
{
    if(L<=l&&r<=R){col[pos]+=v;minn[pos]+=v;return ;}
    int m=(l+r)>>1;down(pos);
    if(L<=m)UPsum(L,R,v,l,m,pos<<1);
    if(R>m)UPsum(L,R,v,m+1,r,pos<<1|1);
    up(pos);
}
stack<int>ma,mi;map<int,int>mp;
int main()
{
    int cas;cin>>cas;int kase=0;
    while(cas--)
    {   
        mp.clear();
        while(!ma.empty())ma.pop();
        while(!mi.empty())mi.pop();
        ans=0;
        scanf("%d",&n);
        build(1,n,1);
        rep(i,1,n)scanf("%d",&a[i]);
        int pre;
        rep(i,1,n)
        {
            while(!ma.empty())//维护单调递减
            {
                int k=ma.top();
                if(a[k]>=a[i])break;

                ma.pop();
                if(ma.empty())pre=1;
                else pre=ma.top()+1;
                UPsum(pre,k,-a[k],1,n,1);
            }
            if(ma.empty())pre=1;
            else pre=ma.top()+1;
            ma.push(i);
            UPsum(pre,i,a[i],1,n,1);

            while(!mi.empty())
            {
                int k=mi.top();
                if(a[k]<=a[i])break;
                mi.pop();
                if(mi.empty())pre=1;
                else pre=mi.top()+1;
                UPsum(pre,k,a[k],1,n,1);
            }
            if(mi.empty())pre=1;
            else pre=mi.top()+1;
            mi.push(i);
            UPsum(pre,i,-a[i],1,n,1);

            if(!mp[a[i]])pre=1;
            else pre=mp[a[i]]+1;
            UPsum(pre,i,-1,1,n,1);
            mp[a[i]]=i;
            ans+=t[1];
        }
        printf("Case #%d: %lld
",++kase,ans);
    }
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/11440564.html