之前写树状数组只写了了单点修改区间查询以及区间修改单点查询.今天因为一个题目要用到树状数组区间修改区间查询,所以先更一下区间修改以及区间查询.
- 区间修改以及区间查询呢,简单的来说区间修改还是和以前一样用一个D[i]数组单点修改即可完成.如何进行区间查询呢?这里我们用到两个数组即可完成,c1[i]表示d[i]的前缀和,c2[i]表示d[i]*(i-1)的前缀和.如此我们就可以进行区间修改以及区间查询了.c1,c2类似之前的sum数组.
直接看这个题,其实树状数组这种数据结构大多数只是一种降低时间复杂度的工具,题目的重点在于思维的过程
求不可重集的计数,大概就是推出相邻两项的关系,然后就知道了一个公式...然后就没了= - =因为不会打公式,啊,求和公式啥的都不会打..
这里的树状数组大概是维护的l区间嘛,然后扫描线的做法统计答案罗..(还是挺复杂的一个蓝题,其实我觉得跟紫题差不多...)
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll N=1e6+5;
ll a[N],n,c1[N],c2[N],last[N],d[N],ls[N];
ll lowbit(ll x) { return x&(-x); }
void add(ll pos,ll val)
{
ll x=pos;
while(pos<=n)
{
c1[pos]+=val;
c2[pos]+=(x-1)*val;
pos+=lowbit(pos);
}
}
ll query(ll pos)
{
ll res=0;ll x=pos;
while(pos)
{
res+=x*c1[pos]-c2[pos];
pos-=lowbit(pos);
}
return res;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) {scanf("%lld",&a[i]);ls[i]=a[i];}
sort(ls+1,ls+1+n);
int cnt=unique(ls+1,ls+1+n)-ls-1;
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(ls+1,ls+1+n,a[i])-ls;
last[i]=d[a[i]];
d[a[i]]=i;
}
ll ans=0,now=0;
for(int i=1;i<=n;i++)
{
now+=2ll*(query(i)-query(last[i]))+i-last[i];
now%=mod;
ans+=now;
ans%=mod;
add(last[i]+1,1);
add(i+1,-1);
}
printf("%lld\n",ans);
return 0;
}
京公网安备 11010502036488号