P7530 题解
xiaofu15191 · · 题解
今天模拟赛遇到的题目。第一眼看上去就像数据结构,可是不会打。以为是分块计数然后算之类的(虽然实际上也能用分块维护)。赛后弄了半天才想通。
首先我们设
接着我们从前往后枚举变量
先考虑此时有哪些左端点可选。发现左端点只可能位于
回过头来,我们来看看枚举变量
首先,我们找到
因此,我们可以使用线段树维护答案,对于每个节点维护其区间内可作为左端点的数字个数
枚举
具体实现可见代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
long long n,num[200010],where[200010],pre[200010];
struct node
{
long long l_num,mid_num,sum,lazy;
}tree[800010];
void pushup(long long now)
{
tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;
tree[now].l_num=tree[now<<1].l_num+tree[now<<1|1].l_num;
tree[now].mid_num=tree[now<<1].mid_num+tree[now<<1|1].mid_num;
}
void pushdown(long long now)
{
tree[now<<1].lazy+=tree[now].lazy;
tree[now<<1].mid_num+=tree[now].lazy;
tree[now<<1].sum+=tree[now].lazy*tree[now<<1].l_num;
tree[now<<1|1].lazy+=tree[now].lazy;
tree[now<<1|1].mid_num+=tree[now].lazy;
tree[now<<1|1].sum+=tree[now].lazy*tree[now<<1|1].l_num;
tree[now].lazy=0;
}
void update_l(long long now,long long l,long long r,long long x,long long k)
{
if(r<x||l>x) return;
if(l==r)
{
tree[now].l_num+=k;
tree[now].sum=tree[now].l_num*tree[now].mid_num;
return;
}
pushdown(now);
long long mid=(l+r)>>1;
if(x<=mid) update_l(now<<1,l,mid,x,k);
else update_l(now<<1|1,mid+1,r,x,k);
pushup(now);
}
void update_mid(long long now,long long l,long long r,long long x,long long y,long long k)
{
if(r<x||l>y) return;
if(x<=l&&r<=y)
{
tree[now].mid_num+=k;
tree[now].lazy+=k;
tree[now].sum+=tree[now].l_num*k;
return;
}
pushdown(now);
long long mid=(l+r)>>1;
if(x<=mid) update_mid(now<<1,l,mid,x,y,k);
if(y>mid) update_mid(now<<1|1,mid+1,r,x,y,k);
pushup(now);
}
long long query(long long now,long long l,long long r,long long x,long long y)
{
if(r<x||l>y) return 0;
if(x<=l&&r<=y) return tree[now].sum;
pushdown(now);
long long mid=(l+r)>>1,res=0;
if(x<=mid) res+=query(now<<1,l,mid,x,y);
if(y>mid) res+=query(now<<1|1,mid+1,r,x,y);
return res;
}
int main()
{
scanf("%lld",&n);
for(long long i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
pre[i]=where[num[i]];
where[num[i]]=i;
}
long long ans=0;
for(long long i=1;i<=n;i++)
{
if(pre[i])
{
update_l(1,1,n,pre[i],-1);
update_mid(1,1,n,pre[pre[i]]+1,pre[i]-1,-1);
}
ans+=query(1,1,n,pre[i]+1,i-1);
update_l(1,1,n,i,1);
update_mid(1,1,n,pre[i]+1,i-1,1);
}
printf("%lld\n",ans);
}