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;
}