JZOJ 6030. 【GDOI2019模拟2019.2.25】白白的

Description

Description

Input

Input

Output

Output

Sample Input

4 3
6 0 10 1
1 2
1 0
1 2

Sample Output

1
1
0

Data Constraint

Data Constraint

Solution

  • 先一遍归并排序算出初始答案。

  • 对于 0 操作,我们需要计算改变的那一位对答案的贡献。

  • 这个就是单点修改+区间查询比 x 大的数的个数,树状数组套权值线段树即可(动态开点)。

  • 对于 1 操作,我们要分裂区间,可以考虑启发式合并,扫短的那边算贡献。

  • 但如果用前面的树套树来算,这部分复杂度将达到 O ( Q   l o g 3 n ) O(Q\ log^3n) O(Q log3n) ,不能接受。

  • 我们发现由于查询时查询的区间(长的那边)是固定的,这是一个突破口。

  • 再开一个一维的权值线段树来维护就可以了!

  • 每次分裂区间时将短的那边多开成一个线段树(最多 Q 个)即可。

  • 这样计算复杂度就是 O ( Q   l o g 2 n ) O(Q\ log^2n) O(Q log2n) 了。

  • 总时间复杂度 O ( ( N + Q )   l o g 2 n ) O((N+Q)\ log^2n) O((N+Q) log2n) ,空间复杂度 O ( N   l o g 2 n ) O(N\ log^2n) O(N log2n)

Code

#include<cstdio>
#include<set>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=150005,inf=1e9+1;
struct data
{
	int s,l,r;
}f[N*30*17];
int n,q,tot,qx,qy,num;
LL ans,cnt;
int a[N],b[N],c[N];
int rt[N],rt1[N],bel[N];
LL val[N];
set<int>ss;
set<int>::iterator it;
inline int read()
{
	int X=0,w=0; char ch=0;
	while(!isdigit(ch)) w|=ch=='-',ch=getchar();
	while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
	return w?-X:X;
}
void solve(int l,int r)
{
	if(l>=r) return;
	int mid=l+r>>1;
	solve(l,mid);
	solve(mid+1,r);
	int j=l,k=mid+1,s=l-1;
	while(j<=mid && k<=r)
		if(b[k]<b[j])
		{
			c[++s]=b[k++];
			cnt+=mid-j+1;
		}else c[++s]=b[j++];
	while(j<=mid) c[++s]=b[j++];
	while(k<=r) c[++s]=b[k++];
	for(int i=l;i<=r;i++) b[i]=c[i];
}
void change(int &v,int l,int r)
{
	if(!v) v=++tot;
	f[v].s+=qy;
	if(l==r) return;
	int mid=l+r>>1;
	if(qx<=mid) change(f[v].l,l,mid); else change(f[v].r,mid+1,r);
}
int find(int v,int l,int r)
{
	if(!v) return 0;
	if(qx<=l && r<=qy) return f[v].s;
	int mid=l+r>>1,s=0;
	if(qx<=mid) s=find(f[v].l,l,mid);
	if(qy>mid) s+=find(f[v].r,mid+1,r);
	return s;
}
inline void add(int x,int y)
{
	qx=y,qy=1;
	while(x<=n)
	{
		change(rt[x],0,inf);
		x+=x&-x;
	}
}
inline void del(int x,int y)
{
	qx=y,qy=-1;
	while(x<=n)
	{
		change(rt[x],0,inf);
		x+=x&-x;
	}
}
inline LL get(int x,int y,int z)
{
	LL s=0;
	if(y>z) return 0;
	qx=y,qy=z;
	while(x)
	{
		s+=find(rt[x],0,inf);
		x-=x&-x;
	}
	return s;
}
int main()
{
	freopen("baibaide.in","r",stdin);
	freopen("baibaide.out","w",stdout);
	n=read(),q=read();
	for(int i=1;i<=n;i++) a[i]=b[i]=read();
	solve(1,n);
	ss.insert(0);
	ss.insert(n+1);
	for(int i=1;i<=n;i++) add(i,a[i]);
	val[num=1]=ans=cnt;
	for(int i=1;i<=n;i++)
	{
		bel[i]=num;
		qx=a[i],qy=1;
		change(rt1[num],0,inf);
	}
	for(int j=1;j<=q;j++)
	{
		int op=read(),x=read();
		if(j>1) x^=ans;
		it=ss.upper_bound(x);
		int r=*it,l=*--it;
		l++,r--;
		if(!op)
		{
			int y=read();
			if(j>1) y^=ans;
			ans^=val[bel[l]];
			LL sum=get(x-1,a[x]+1,inf)-get(l-1,a[x]+1,inf);
			sum+=get(r,0,a[x]-1)-get(x,0,a[x]-1);
			val[bel[l]]-=sum;
			del(x,a[x]);
			qx=a[x],qy=-1;
			change(rt1[bel[l]],0,inf);
			a[x]=y;
			add(x,y);
			qx=y,qy=1;
			change(rt1[bel[l]],0,inf);
			sum=get(x-1,y+1,inf)-get(l-1,y+1,inf);
			sum+=get(r,0,y-1)-get(x,0,y-1);
			val[bel[l]]+=sum;
			ans^=val[bel[l]];
		}else
		{
			ss.insert(x);
			if(x-l<r-x)
			{
				int pos=bel[r];
				for(int i=l;i<=x;i++)
				{
					qx=a[i],qy=-1;
					change(rt1[pos],0,inf);
				}
				ans^=val[pos];
				for(int i=l;i<=x;i++)
				{
					qx=0,qy=a[i]-1;
					val[pos]-=find(rt1[pos],0,inf);
				}
				if(l<x)
				{
					num++;
					for(int i=l;i<x;i++) bel[i]=num;
					for(int i=l;i<x;i++)
					{
						qx=a[i],qy=1;
						change(rt1[num],0,inf);
					}
					int len=cnt=0;
					for(int i=l;i<x;i++) b[++len]=a[i];
					solve(1,len);
					val[num]=cnt;
					ans^=cnt;
					qx=a[x]+1,qy=inf;
					cnt+=find(rt1[num],0,inf);
					val[pos]-=cnt;
				}
				ans^=val[pos];
			}else
			{
				int pos=bel[l];
				for(int i=x;i<=r;i++)
				{
					qx=a[i],qy=-1;
					change(rt1[pos],0,inf);
				}
				ans^=val[pos];
				for(int i=x;i<=r;i++)
				{
					qx=a[i]+1,qy=inf;
					val[pos]-=find(rt1[pos],0,inf);
				}
				if(x<r)
				{
					num++;
					for(int i=x+1;i<=r;i++) bel[i]=num;
					for(int i=x+1;i<=r;i++)
					{
						qx=a[i],qy=1;
						change(rt1[num],0,inf);
					}
					int len=cnt=0;
					for(int i=x+1;i<=r;i++) b[++len]=a[i];
					solve(1,len);
					val[num]=cnt;
					ans^=cnt;
					qx=0,qy=a[x]-1;
					cnt+=find(rt1[num],0,inf);
					val[pos]-=cnt;
				}
				ans^=val[pos];
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值