L. Continuous Intervals解题报告
题干
codeforce
拉米斯是一个聪明的女孩。她对关于数列及其区间的问题很感兴趣。
这里她给你看了一个长度为 \(n\) 的数列,里面全是正整数,记作 \(a_1, a_2, a_3, ⋯, a_n\)。她对那些区间感到非常惊讶,这些区间是 \(a_1, a_2, ⋯, a_n\) 的连续子序列,由几个连续的数字组成,她称它们为连续区间。
更确切地说,考虑一个区间 \(a_l, a_{l+1}, ⋯, a_{r−1}, a_r\),其中 \(1≤l≤r≤n\)。如果在对该区间排序后,任意两个相邻元素的差都小于或等于 \(1\),那么这个区间就被认为是连续的。
作为她最好的朋友,你们从四面八方赶来,跋山涉水来到宁夏,帮助她计算这个数列中连续区间的数量。
前言
听说是个trick,但我确实是想不到,但真理解了思路确实挺妙。
扫描线思想
可以发现对于一个区间\([l,r]\)当且仅当满足下面的式子,区间为连续区间:
我们可以利用扫描线思想,扫描右端点,并把扫描过的端点当做左端点,并用线段树维护这些左端点对该右端点的贡献,累计贡献即为答案。
关键在于贡献怎么维护。为方便处理可以把上面的式子转化为:
接着观察影响该式子的各项:
max的维护
可以利用单调栈,维护一个单调递减的栈(栈中是一个一个的区间块,该区间块上所有点到当前右端点的最大值相同),当加入一个新的端点,比较大小关系,若该点改变了前一个区间块的最大值,就在线段树上进行区间更新,更新大小为最大值的变化量。
min的维护
同理可以用单调栈,维护一个单调递增的栈,更新量为最小值的变化量。
cnt的维护
可以离散化或用 map 来记录上一次各值出现的位置(初始化为零),每加入一个端点,就更新上一次出现位置的后一位到该点位置,更新量为 -1 (\(cnt\)增加1)
统计答案
可以发现若区间不满足连续区间性质,则一定有:
因为一定有解,所以根节点最小值一定为 -1 ,根节点统计的数量即为答案。
code
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<vector>
#include<deque>
#include<queue>
#include<iomanip>
#include<bitset>
#include<unordered_map>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
const int maxn=1e5+5;
int t,n;
struct nd
{
int l,r,cnt,mi,tag;
}v[maxn<<2];
void build(int rt,int l,int r)
{
v[rt].l=l,v[rt].r=r;v[rt].tag=0;v[rt].mi=0;
if(l==r)
{
v[rt].cnt=1;//叶子最小值一定是它本身
return;
}
int mid=(l+r)>>1;
build(lson,l,mid),build(rson,mid+1,r);
}
void pushup(int rt)
{
if(v[lson].mi==v[rson].mi)
{
v[rt].mi=v[lson].mi;
v[rt].cnt=v[lson].cnt+v[rson].cnt;
}
else if(v[lson].mi<v[rson].mi)
{
v[rt].mi=v[lson].mi;
v[rt].cnt=v[lson].cnt;
}
else
{
v[rt].mi=v[rson].mi;
v[rt].cnt=v[rson].cnt;
}
}
void pushdown(int rt)
{
if(v[rt].tag)
{
int lz=v[rt].tag;
v[rt].tag=0;
v[lson].tag+=lz,v[rson].tag+=lz;
v[lson].mi+=lz,v[rson].mi+=lz;
}
}
void update(int rt,int L,int R,int val)
{
if(v[rt].l>=L&&v[rt].r<=R)
{
v[rt].mi+=val;
v[rt].tag+=val;
return;
}
pushdown(rt);
int mid=(v[rt].l+v[rt].r)>>1;
if(L<=mid) update(lson,L,R,val);
if(R>mid) update(rson,L,R,val);
pushup(rt);
}
pair<int,int> skma[maxn],skmi[maxn];
int topma,topmi;
unordered_map<int,int> q;
signed main()
{
t=read();
for(int ss=1;ss<=t;ss++)
{
n=read();
build(1,1,n);
long long ans=0;
q.clear();topmi=topma=0;
for(int i=1,op;i<=n;i++)
{
op=read();
int last=i;
while(topma&&op>=skma[topma].first)
{
update(1,skma[topma].second,last-1,op-skma[topma].first);
last=skma[topma].second;
topma--;
}
skma[++topma]={op,last};//维护max影响
last=i;
while(topmi&&op<=skmi[topmi].first)
{
update(1,skmi[topmi].second,last-1,skmi[topmi].first-op);
last=skmi[topmi].second;
topmi--;
}
skmi[++topmi]={op,last};//维护min
if(q[op]) update(1,q[op]+1,i,-1);
else update(1,1,i,-1);
q[op]=i;//维护cnt
ans+=v[1].cnt;//统计答案
}
printf("Case #%d: %lld\n",ss,ans);
}
return 0;
}

浙公网安备 33010602011771号