之前写树状数组只写了了单点修改区间查询以及区间修改单点查询.今天因为一个题目要用到树状数组区间修改区间查询,所以先更一下区间修改以及区间查询.
- 区间修改以及区间查询呢,简单的来说区间修改还是和以前一样用一个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; }