【树套树】【BZOJ 2141】排队

本文介绍了一种使用线段树进行区间更新和查询的高效算法,通过实例讲解了如何构建和操作线段树,以解决复杂的数据结构问题。算法涵盖了插入、查询、更新等关键操作,并详细解释了代码实现细节。

题目

在这里插入图片描述

思路

在这里插入图片描述

代码

#include<bits/stdc++.h>
#define N 200002
#define M 5000002
using namespace std;
int n,m,q[N],ans;
int hs[N],tot,num[M];
int sum[M],root[N],ls[M],rs[M],sz;
void insert(int &k,int l,int r,int w,int f)
{
	if(!k)k=++sz;sum[k]+=f;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(w<=mid)insert(ls[k],l,mid,w,f);
	else insert(rs[k],mid+1,r,w,f);
}
int query(int &k,int l,int r,int a,int b)
{
	if(!k)return 0;int mid=(l+r)>>1;
	if(a<=l&&b>=r)return sum[k];
	if(b<=mid)return query(ls[k],l,mid,a,b);
	else if(a>mid)return query(rs[k],mid+1,r,a,b);
	else return query(ls[k],l,mid,a,mid)+query(rs[k],mid+1,r,mid+1,b);
}
void ins(int pos,int w,int f)
{
	int l=1,r=tot,k=1;
	while(l!=r)
	{
		int mid=(l+r)>>1;
		insert(root[k],1,n,pos,f);
		if(w<=mid)k=k<<1,r=mid;
		else k=k<<1|1,l=mid+1;
	}insert(root[k],1,n,pos,f);
}
int ask_bit(int a,int b,int w)
{
	int l=1,r=tot,k=1,ret=0;
	while(l!=r)
	{
		int mid=(l+r)>>1;
		if(w<=r&&w>mid)
		{
			ret+=query(root[k<<1],1,n,a,b);
			k=k<<1|1,l=mid+1;
		}
		else
			k=k<<1,r=mid;
	}return ret;
} 
int ask_big(int a,int b,int w)
{
	int l=1,r=tot,k=1,ret=0;
	while(l!=r)
	{
		int mid=(l+r)>>1;
		if(w>=l&&w<=mid)
		{
			ret+=query(root[k<<1|1],1,n,a,b);
			k=k<<1,r=mid;
		}
		else k=k<<1|1,l=mid+1;
	}return ret;
}
int x[N],y[N],cnt;
void init()
{
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&q[i]);
		num[++cnt]=q[i];
	}scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x[i],&y[i]);
		num[++cnt]=x[i];
		num[++cnt]=y[i];
	}sort(num+1,num+1+cnt);
	num[0]=-(1<<30);
	for(int i=1;i<=cnt;i++)
		if(num[i]!=num[i-1])
			hs[++tot]=num[i];
}
int find(int x)
{
	int l=1,r=tot,ret;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(hs[mid]<=x)
			l=mid+1,ret=mid;
		else r=mid-1;
	}
	return ret;
}
int main()
{
	scanf("%d",&n);init();
	for(int i=1;i<=n;i++)
	{
		int ii=find(q[i]);
		ans+=ask_big(1,i,ii);
		ins(i,ii,1);
	}
	printf("%d\n",ans);
	for(int i=1;i<=m;i++)
	{
		int a=x[i],b=y[i];
		if(a>b)swap(a,b);
		int ia=find(q[a]),ib=find(q[b]);
		ans-=ask_big(a+1,b,ib);
		ans+=ask_bit(a+1,b,ib);
		ans-=ask_bit(a,b-1,ia);
		ans+=ask_big(a,b-1,ia);
		if(ia>ib)ans--;
		else if(ia<ib)ans++;
		ins(a,ia,-1);ins(b,ib,-1);
		ins(a,ib,1);ins(b,ia,1);
		swap(q[a],q[b]);
		printf("%d\n",ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值