P6477-[NOI Online #2 提高组]子序列问题【线段树】

正题

题目链接:https://www.luogu.com.cn/problem/P6477
话说这是luogu的冥间数据


题目大意

n n 个数的序列, f ( l , r ) f(l,r) 表示 l r l\sim r 有多少个不同的数字。

l = 1 n r = l n ( f ( l , r ) ) 2 \sum_{l=1}^n\sum_{r=l}^n(f(l,r))^2


解题思路

考虑多一个数字会多出 2 n + 1 2n+1 (n表示原来数字个数)。

线段树维护 f ( 1 i 1 , i ) f(1\sim i-1,i) 的和,然后每个数字能影响的范围是i到上一个和它相同的数字的后一个位置处,我们修改这部分的数据然后每次统计答案即可。


c o d e code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define lowbit(x) (x&-x)
#define siz(x) (t[x].r-t[x].l+1)
#define k(x) (((x)>XJQ)?((x)-XJQ):(x))
#define ll long long
using namespace std;
const ll N=1e6+10,XJQ=1e9+7;
ll n,ans,answer;
ll a[N],b[N],last[N],v[N];
ll read() {
	ll x=0,f=1; char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x*f;
}
struct Seq_Tree{
	struct Tree_node{
		ll l,r,val,lazy;
	}t[N*4];
	void Build(ll x,ll l,ll r){
		t[x].l=l;t[x].r=r;
		if(l==r)return;
		ll mid=(l+r)>>1;
		Build(x*2,l,mid);
		Build(x*2+1,mid+1,r);
		return;
	}
	void DownData(ll x){
		if(!t[x].lazy)return;
		(t[x*2].lazy+=t[x].lazy)%=XJQ;
		(t[x*2+1].lazy+=t[x].lazy)%=XJQ;
		(t[x*2].val+=t[x].lazy*siz(x*2))%=XJQ;
		(t[x*2+1].val+=t[x].lazy*siz(x*2+1))%=XJQ;
		t[x].lazy=0;return;
	}
	void Change(ll x,ll l,ll r,ll val){
		if(t[x].l==l&&t[x].r==r){
			(t[x].lazy+=val)%=XJQ;
			(t[x].val+=val*siz(x))%=XJQ;
			return;
		}
		DownData(x);
		ll mid=(t[x].l+t[x].r)>>1;
		if(r<=mid) Change(x*2,l,r,val);
		else if(l>mid) Change(x*2+1,l,r,val);
		else Change(x*2,l,mid,val),Change(x*2+1,mid+1,r,val);
		t[x].val=(t[x*2].val+t[x*2+1].val)%XJQ;
		return;
	}
	ll Ask(ll x,ll l,ll r){
		if(t[x].l==l&&t[x].r==r)
			return t[x].val;
		DownData(x);
		ll mid=(t[x].l+t[x].r)>>1;
		if(r<=mid) return Ask(x*2,l,r);
		if(l>mid) return Ask(x*2+1,l,r);
		return (Ask(x*2,l,mid)+Ask(x*2+1,mid+1,r))%XJQ;
	}
}T;
int main()
{
	n=read();
	for(ll i=1;i<=n;i++)
		a[i]=b[i]=read();
	sort(b+1,b+1+n);
	ll m=unique(b+1,b+1+n)-b-1;
	for(ll i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+1+m,a[i])-b;
		last[i]=v[a[i]];v[a[i]]=i;
	}
	T.Build(1,1,n);
	T.Change(1,1,1,1);
	ans=answer=1;
	for(ll i=2;i<=n;i++){
		(ans+=2*T.Ask(1,last[i]+1,i)+i-last[i])%=XJQ;
		T.Change(1,last[i]+1,i,1);(answer+=ans)%=XJQ;
	}
	printf("%lld",answer);
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/106321200
今日推荐