树套树

1.树状数组套动态开点权值线段树

【例题】P3157 [CQOI2011]动态逆序对

【题意】

带删除操作的动态求逆序对个数

【分析】

其实这道题没有强制在线,可以用cdq分治来解决

但是我们选择来练习线段树的话,就要用到树状数组套线段树,感觉思想很暴力

就是每次计算删除这个数对左右的影响个数,再在删除后给左右的影响处理掉即可

就是码量

【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int n,m;
int a1[maxn],a2[maxn];
int c[maxn],b[maxn],a[maxn];
int lowbit(int x)
{
	return x&(-x);
}
struct segtree
{
	int l,r,sum;
}tr[maxn*235];
int getsum(int x)
{
	int res=0;
	while(x>0)
	{
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}
void add(int x,int y)
{
	while(x<=n)
	{
		c[x]+=y;
		x+=lowbit(x);
	}
}
int root[maxn],tot;
int query(int &now,int L,int R,int l,int r)
{
	if(!now) now=++tot;
	if(l>r) return 0;
	if(L>=l && R<=r) return tr[now].sum;
	int mid=L+R>>1,res=0;
	if(l<=mid) res+=query(tr[now].l,L,mid,l,r);
	if(mid<r) res+=query(tr[now].r,mid+1,R,l,r);
	return res;
}
int calcmin(int l,int r,int val)
{
	int res=0;
	for(int i=r;i>0;i-=lowbit(i)) res+=query(root[i],1,n,1,val);
	for(int i=l;i>0;i-=lowbit(i)) res-=query(root[i],1,n,1,val);
	return res;
}
int calcmax(int l,int r,int val)
{
	int res=0;
	for(int i=r;i>0;i-=lowbit(i)) res+=query(root[i],1,n,val,n);
	for(int i=l;i>0;i-=lowbit(i)) res-=query(root[i],1,n,val,n);
	return res;
}
void pushup(int now)
{
	tr[now].sum=tr[tr[now].l].sum+tr[tr[now].r].sum;
}
void update(int &now,int L,int R,int x,int val)
{
	if(!now) now=++tot;
	if(L==R)
	{
		tr[now].sum+=val;
		return;
	}
	int mid=L+R>>1;
	if(x<=mid) update(tr[now].l,L,mid,x,val);
	if(mid<x) update(tr[now].r,mid+1,R,x,val);
	pushup(now);
}
int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[a[i]]=i;
	long long ans=0;
	for(int i=1;i<=n;i++)
	{
		a1[i]=getsum(n)-getsum(a[i]);
		ans+=a1[i];
		add(a[i],1);
	}
	ans=0;
	memset(c,0,sizeof(c));
	for(int i=n;i>=1;i--)
	{
		a2[i]+=getsum(a[i]-1);
		ans+=a2[i];
		add(a[i],1);
	}
	int x;
//	for(int i=1;i<=n;i++) printf("%d %d\n",a1[i],a2[i]);
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j+=lowbit(j))
			update(root[j],1,n,a[i],1);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&x); int pos=b[x];
		printf("%lld\n",ans);
	/*	int del=a1[b[x]]+a2[b[x]]-calcmax(1,b[x]-1,x)-calcmin(b[x]+1,n,x);
		ans-=del;
		for(int j=b[x];j<=n;j+=lowbit(j)) update(root[j],1,n,x,1);*/
		for(int j=pos-1;j;j-=lowbit(j))
			ans-=query(root[j],1,n,a[pos]+1,n);
		for(int j=n;j;j-=lowbit(j))
			ans-=query(root[j],1,n,1,a[pos]-1);
		for(int j=pos;j;j-=lowbit(j))
			ans+=query(root[j],1,n,1,a[pos]-1);
		for(int j=pos;j<=n;j+=lowbit(j))
			update(root[j],1,n,a[pos],-1);
	}
	return 0;
}

【练习】bzoj2141. 排队

【题意】带交换的动态求逆序对

【分析】和例题基本一致,主要就是再写一遍练习一下

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,m,v[maxn];
int c[maxn];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int v)
{
	while(x<=n)
	{
		c[x]+=v;
		x+=lowbit(x);
	}
}
int getsum(int x)
{
	int res=0;
	while(x>0)
	{
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}
struct segtree
{
	int l,r,sum;
}tr[maxn<<5];
int cnt,ans,ls[maxn],root[maxn];
#define lson tr[now].l
#define rson tr[now].r
void update(int &now,int L,int R,int pos,int val)
{
	if(!now) now=++cnt;
	if(L==R)
	{
		tr[now].sum+=val;
		return;
	}
	int mid=L+R>>1;
	if(pos<=mid) update(tr[now].l,L,mid,pos,val);
	else update(tr[now].r,mid+1,R,pos,val);
	tr[now].sum=tr[lson].sum+tr[rson].sum; 
}
int query(int now,int L,int R,int l,int r)
{
	if(L>R) return 0;
	if(L>=l && R<=r) return tr[now].sum;
	int mid=L+R>>1,res=0;
	if(l<=mid) res+=query(lson,L,mid,l,r);
	if(mid<r) res+=query(rson,mid+1,R,l,r);
	return res;
}
int Query(int L,int R,int l,int r)
{
	if(L>R || l>r) return 0;
	int res=0;
	L--;
	for(;R;R-=lowbit(R)) res+=query(root[R],0,n+1,l,r);
	for(;L;L-=lowbit(L)) res-=query(root[L],0,n+1,l,r);
	return res;
}
int main()
{
	freopen("lineup.in","r",stdin);
	freopen("lineup.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&v[i]),ls[i]=v[i];
	sort(ls+1,ls+n+1);
	int cnt=unique(ls+1,ls+n+1)-ls-1;
	for(int i=1;i<=n;i++)
		v[i]=lower_bound(ls+1,ls+n+1,v[i])-ls;
	for(int i=1;i<=n;i++)
	{
		ans+=getsum(n)-getsum(v[i]);
		add(v[i],1);
	}
	printf("%d\n",ans);
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j+=lowbit(j))
			update(root[j],0,n+1,v[i],1);
	scanf("%d",&m);
	int x,y;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		if(x>y) swap(x,y);
		ans+=Query(x+1,y-1,0,v[y]-1);
		ans-=Query(x+1,y-1,v[y]+1,n);
		ans+=Query(x+1,y-1,v[x]+1,n);
		ans-=Query(x+1,y-1,0,v[x]-1);
		for(int j=y;j<=n;j+=lowbit(j))
			update(root[j],0,n+1,v[x],1),update(root[j],0,n+1,v[y],-1);
		for(int j=x;j<=n;j+=lowbit(j))
			update(root[j],0,n+1,v[x],-1),update(root[j],0,n+1,v[y],1);
		if(v[x]>v[y]) ans--;
		if(v[x]<v[y]) ans++;
		swap(v[x],v[y]);
		printf("%d\n",ans);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值