bzoj 3744: Gty的妹子序列 分块+主席树

Description

我早已习惯你不在身边,
人间四月天 寂寞断了弦。
回望身后蓝天,
跟再见说再见……
某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现
她们排成了一个序列,每个妹子有一个美丽度。
Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:“你知道区间
[l,r]中妹子们美丽度的逆序对数吗?”
蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:“强制在线。”
请你帮助一下Autumn吧。
给定一个正整数序列a,对于每次询问,输出al…ar中的逆序对数,强制在线。
Input

第一行包括一个整数n(1<=n<=50000),表示数列a中的元素数。
第二行包括n个整数a1…an(ai>0,保证ai在int内)。
接下来一行包括一个整数m(1<=m<=50000),表示询问的个数。
接下来m行,每行包括2个整数l、r(1<=l<=r<=n),表示询问al…ar中的逆序
对数(若ai>aj且i<j,则为一个逆序对)。
l,r要分别异或上一次询问的答案(lastans),最开始时lastans=0。
保证涉及的所有数在int内。
Output

对每个询问,单独输出一行,表示al…ar中的逆序对数。

Sample Input

4

1 4 2 3

1

2 4

Sample Output

2

分析:
求区间逆序对树。
一种简单的想法,先分块,预处理出 a n s [ i ] [ j ] ans[i][j] ans[i][j]表示从第 i i i块头到位置 j j j的逆序对数,预处理这个是 O ( n n l o g n ) O(n\sqrt{n}logn) O(nn logn)的。
然后对于一个询问,左边的散块直接找在他后面小于他的数的个数,主席树解决。

代码:

/**************************************************************
    Problem: 3744
    User: liangzihao
    Language: C++
    Result: Accepted
    Time:10680 ms
    Memory:104252 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define LL long long
 
const int maxn=5e4+7;
 
using namespace std;
 
int n,block,cnt,m;
int a[maxn],b[maxn],c[maxn],bel[maxn],l[231],r[231],root[maxn];
LL sum[231][maxn],ans,x,y;
 
struct node{
    int l,r,data;
}t[maxn*20];
 
void build_block()
{
    block=trunc(sqrt(n));
    cnt=n/block+(n%block!=0);
    for (int i=1;i<=cnt;i++)
    {
        l[i]=(i-1)*block+1;
        r[i]=i*block;
    }
    r[cnt]=n;
    for (int i=1;i<=n;i++) bel[i]=(i-1)/block+1;
}
 
void updata(int x,int k)
{
    for (int i=x;i<=n;i+=i&(-i)) c[i]+=k;
}
 
int getsum(int x)
{
    int sum=0;
    for (int i=x;i>0;i-=i&(-i)) sum+=c[i];
    return sum;
}
 
void ins(int &p,int q,int l,int r,int x)
{
    if (!p) p=++cnt;
    t[p].data=t[q].data+1;
    if (l==r) return;
    int mid=(l+r)/2;
    if (x<=mid) t[p].r=t[q].r,ins(t[p].l,t[q].l,l,mid,x);
           else t[p].l=t[q].l,ins(t[p].r,t[q].r,mid+1,r,x);
}
 
int getsum(int p,int q,int l,int r,int x,int y)
{
    if (t[p].data-t[q].data<=0) return 0;
    if ((l==x) && (r==y)) return t[p].data-t[q].data;
    int mid=(l+r)/2;
    if (y<=mid) return getsum(t[p].l,t[q].l,l,mid,x,y);
    else if (x>mid) return getsum(t[p].r,t[q].r,mid+1,r,x,y);
    else return getsum(t[p].l,t[q].l,l,mid,x,mid)+getsum(t[p].r,t[q].r,mid+1,r,mid+1,y);
}
 
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    int size=unique(b+1,b+n+1)-b-1;
    for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+size+1,a[i])-b;
    build_block();  
    for (int i=1;i<=n;i+=block)
    {
        int x=bel[i];
        for (int j=i;j<=n;j++)
        {
            int d=j-i-getsum(a[j]);
            sum[x][j]=sum[x][j-1]+(LL)d;
            updata(a[j],1);
        }
        memset(c,0,sizeof(c));
    }   
    for (int i=1;i<=n;i++) ins(root[i],root[i-1],1,n,a[i]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&x,&y);
        x^=ans,y^=ans;
        if (l[bel[x]]==x) ans=sum[bel[x]][y];
        else
        {
            ans=sum[bel[x]+1][y];
            for (int i=x;i<=min(r[bel[x]],(int)y);i++)
            {
                ans+=(LL)getsum(root[y],root[i-1],1,n,1,a[i]-1);
            }
        }
        printf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值