Codeforces Round #407 (Div. 1) E. New task(线段树+树状数组)

原题链接:http://codeforces.com/contest/788/problem/E


题解:

先离散化,然后通过两个树状数组处理出ai<=aj (i<j)的对数,和ai>=aj (i<j) 的对数,然后,对于每一种数字建立一颗线段树,其中线段树维护六个值为:

L:这个区间中,ai<=aj (i<j)的对数。

R:这个区间中,ai>=aj (i<j) 的对数。

M:这个节点中数的个数。

LM:这个区间中,三元组满足 ai<=aj ==ap(i<j<p) 的组数。

RM:这个区间中,三元组满足 ai==aj>=ap (i<j<p) 的组数。

LMR:这个区间中,五元组满足 ai<=aj==ak==ap>=aq (i<j<k<p<q) 的组数


对于更新操作,每次只更新一条链即可,其中

L=(lson->L+rson->L);
M=(lson->M+rson->M);
R=(lson->R+rson->R);
LM=(lson->LM+rson->LM+lson->L*rson->M);
MR=(lson->MR+rson->MR+lson->M*rson->R);
LMR=(lson->LMR+rson->LMR+lson->LM*rson->R+lson->L*rson->MR);


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
const int MOD=1e9+7;
int al[MAXN],ar[MAXN],a[MAXN];
int Hash[MAXN];
int id[MAXN],num[MAXN],pos[MAXN];
int cnt=1;
struct node
{
	int l,r;
	node *lson,*rson;
	ll L,M,R,LM,MR,LMR;
	node(int _l,int _r):l(_l),r(_r)
	{
		if(l==r)
		{
			return ;
		}
		int m=(l+r)>>1;
		lson=new node(l,m);
		rson=new node(m+1,r);
	}
	void update(int k,int l,int r,int ID)
	{
		if(l==r)
		{
			L=pos[ID]*al[ID];
			M=pos[ID];
			R=pos[ID]*ar[ID];
			LM=MR=LMR=0;
			//printf("%lld %lld %lld\n",L,M,R);
			return ;
		}
		int m=(l+r)>>1;
		if(k<=m)
			lson->update(k,l,m,ID);
		if(k>m)	
			rson->update(k,m+1,r,ID);
		L=(lson->L+rson->L)%MOD;
		M=(lson->M+rson->M)%MOD;
		R=(lson->R+rson->R)%MOD;
		LM=(lson->LM+rson->LM+lson->L*rson->M)%MOD;
		MR=(lson->MR+rson->MR+lson->M*rson->R)%MOD;
		LMR=(lson->LMR+rson->LMR+lson->LM*rson->R+lson->L*rson->MR)%MOD;
	}
}*sv[MAXN];
struct bit
{
	int n;
	ll a[MAXN];
	void init(int _n)
	{
		memset(a,0,sizeof(a));
		n=_n;
	}
	int lowbit(int x)
	{
		return x&(-x);
	}
	void update(int x,int add)
	{
		while(x<=n)
		{
			a[x]+=add;
			x+=lowbit(x);
		}
	}
	ll query(int x)
	{
		ll ret=0;
		while(x)
		{
			ret+=a[x];
			ret%=MOD;
			x-=lowbit(x);
		}
		return ret;
	}
}LT,RT;
int getid(int x)
{
	int ret=lower_bound(Hash+1,Hash+cnt+1,x)-Hash;
	return ret;
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int n;
	scanf("%d",&n);
	LT.init(n),RT.init(n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		Hash[cnt++]=a[i];
		pos[i]=1;
	}
	sort(Hash+1,Hash+cnt);
	cnt=unique(Hash+1,Hash+cnt)-Hash-1;
	for(int i=1;i<=n;i++)
	{
		a[i]=getid(a[i]);
		id[i]=++num[a[i]];
	}
	for(int i=1;i<=n;i++)
	{
		al[i]=LT.query(a[i]);
		LT.update(a[i],1);
	}
	for(int i=n;i>=1;i--)
	{
		ar[i]=RT.query(a[i]);
		RT.update(a[i],1);
	}
	for(int i=1;i<=cnt;i++)
	{
		sv[i]=new node(1,num[i]);
	}
	for(int i=1;i<=n;i++)
	{
		sv[a[i]]->update(id[i],1,num[a[i]],i);
	}
	ll ans=0;
	for(int i=1;i<=cnt;i++)
	{
		ans+=sv[i]->LMR;
		ans%=MOD;
	}
	int m;
	scanf("%d",&m);
	while(m--)
	{
		int q,at;
		scanf("%d%d",&q,&at);
		ans=(ans-sv[a[at]]->LMR+MOD)%MOD;
		pos[at]^=1;
		sv[a[at]]->update(id[at],1,num[a[at]],at);
		ans=(ans+sv[a[at]]->LMR)%MOD;
		printf("%lld\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值