您的位置:首页 > 其它

bzoj2141 分块套树状数组/树套树

2017-10-26 16:55 267 查看
题意:动态维护逆序对,每次会交换两个数。

首先离散一波。

然后这题其实很显然,分块处理先,然后对于每次交换,只有在x,y之间的才有用。

那么在bl[x]+1和bl[y]-1之间的数都是整块,可以直接用bit维护。

否则就是一个块内的,就可以直接暴力维护了。

感觉我的实现姿势不好,写的很丑,看了po姐的感觉惭愧。。于是重新来一了几发。

树套树也可以做。以后回来填坑。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
int bl
,n,m;
int cnt[200]
,pre
,a
,ans;
struct node
{
int x,y;
}b
;
bool cmp(node a,node b)
{
return a.x<b.x;
}
inline int lowbit(int x)
{
return x&(-x);
}
inline void add(int t[],int x)
{
while (x<=n)
{
++t[x];
x+=lowbit(x);
}
}
inline void decrease(int t[],int x)
{
while (x<=n)
{
t[x]--;
x+=lowbit(x);
}
}
inline int get(int t[],int x)
{
int ans=0;
while (x>0)
{
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
scanf("%d",&n);
fo(i,1,n)
scanf("%d",&b[i].x),b[i].y=i;
sort(b+1,b+1+n,cmp);
int tot=0;
fo(i,1,n)
{
if (b[i].x!=b[i-1].x)++tot;
a[b[i].y]=tot;
}
fd(i,n,1)
{
ans+=get(pre,a[i]-1);
add(pre,a[i]);
}
int c=sqrt(n);
//int c=static_cast<int>(sqrt(n)+1e-7);
fo(i,1,n)add(cnt[(i-1)/c],a[i]);
printf("%d\n",ans);
scanf("%d",&m);
while (m--)
{
int x,y;
scanf("%d%d",&x,&y);
if (x>y)swap(x,y);
int l=(x-1)/c,r=(y-1)/c;
l++,r--;
if (l<=r)
{
fo(i,l,r)
{
ans-=get(cnt[i],a[x]-1);
ans+=get(cnt[i],n)-get(cnt[i],a[x]);
ans+=get(cnt[i],a[y]-1);
ans-=get(cnt[i],n)-get(cnt[i],a[y]);
}
fo(i,x+1,l*c)
{
if (a[i]<a[x])--ans;
if (a[i]>a[x])++ans;
if (a[i]<a[y])++ans;
if (a[i]>a[y])--ans;
}
fo(i,(r+1)*c+1,y-1)
{
if (a[i]<a[x])--ans;
if (a[i]>a[x])++ans;
if (a[i]<a[y])++ans;
if (a[i]>a[y])--ans;
}
}
else
{
fo(i,x+1,y-1)
{
if (a[i]<a[x])--ans;
if (a[i]>a[x])++ans;
if (a[i]<a[y])++ans;
if (a[i]>a[y])--ans;
}
}
if (a[x]>a[y])ans--;
else if (a[x]<a[y])ans++;
decrease(cnt[(x-1)/c],a[x]);
decrease(cnt[(y-1)/c],a[y]);
swap(a[x],a[y]);
add(cnt[(x-1)/c],a[x]);
add(cnt[(y-1)/c],a[y]);
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: