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

3744: Gty的妹子序列

Time Limit: 15 Sec  Memory Limit: 128 MB
Submit: 101  Solved: 34
[Submit][Status]

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

  这种常数优化的题目的确需要思维的灵活性,尽量少调用中心函数,例如本题,可以通过预处理将询问中每次循环调用的主席树次数由三次降为一次,而这样预处理又会超时,通过“仔细观(luan)察(gao)”,发现预处理的两个数组可通过询问for语句中调用主席树的询问范围省略为预处理一个数组,及res1[i][j]表示从第i块开头到第j个数的逆序对数。当然,也可以通过微调块的大小,进行优化。最后,每次主席树调用由于询问的时相同的区间,顾只用调用一次就把两次主席树询问处理完,这个优化处于程序中心,能够把程序从1.8s优化为1.4s。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
#define MAXN 50010
#define MAXT 3200000
#define MAXB1 240
#define INF 0x3f3f3f3f
int n,m;
struct sgt_node
{
        int lch,rch;
        int t;
}sgt[MAXT];
int topt=0;
void Add_sgt(int &now,int base,int l,int r,int pos)
{
        now=++topt;
        sgt[now]=sgt[base];
        sgt[now].t++;
        if (l==r)return ;
        if (pos<=((l+r)>>1))
                Add_sgt(sgt[now].lch,sgt[base].lch,l,(l+r)>>1,pos);
        else
                Add_sgt(sgt[now].rch,sgt[base].rch,((l+r)>>1)+1,r,pos);
}
int Qry_sgt(int now1,int now2,int l,int r,int x,int y)
{
        if (!now1 && !now2)return 0;
        if (l==x && r==y)
                return sgt[now1].t-sgt[now2].t;
        int mid=(l+r)>>1;
        if (y<=mid)
                return Qry_sgt(sgt[now1].lch,sgt[now2].lch,l,mid,x,y);
        else if (mid<x)
                return Qry_sgt(sgt[now1].rch,sgt[now2].rch,mid+1,r,x,y);
        else
                return Qry_sgt(sgt[now1].lch,sgt[now2].lch,l,mid,x,mid)
                        + Qry_sgt(sgt[now1].rch,sgt[now2].rch,mid+1,r,mid+1,y);
}
int roof[MAXN];
int Qry_tot(int rl,int rr,int x,int y)
{
        return Qry_sgt(roof[rr],roof[rl-1],1,m,x,y);
}

int num[MAXN];
int bs[MAXB1],bt[MAXB1];
int bres1[MAXB1][MAXN];
struct aaa
{
        int pos,val;
}a[MAXN];
bool cmp_pos(aaa a1,aaa a2)
{
        return a1.pos<a2.pos;
}
bool cmp_val(aaa a1,aaa a2)
{
        return a1.val<a2.val;
}
int tarr[MAXN];
void Add_val(int pos)
{
        while (pos<MAXN)
        {
                tarr[pos]++;
                pos+=pos&(-pos);
        }
}
int Qry_sum(int pos)
{
        int ret=0;
        while (pos)
        {
                ret+=tarr[pos];
                pos-=pos&(-pos);
        }
        return ret;
}
int main()
{
        freopen("input.txt","r",stdin);
        //freopen("output.txt","w",stdout);
        scanf("%d",&n);
        int i,j,k;
        int x,y,z;
        for (i=1;i<=n;i++)
        {
                scanf("%d",&a[i].val);
                a[i].pos=i;
        }
        sort(a+1,a+n+1,cmp_val);
        m=0;
        for (i=1;i<=n;i++)
        {
                if (i==1 || a[i].val!=x)
                {
                        x=a[i].val;
                        a[i].val=++m;
                }else
                {
                        a[i].val=m;
                }
        }
        sort(a+1,a+n+1,cmp_pos);
        for (i=1;i<=n;i++)
                num[i]=a[i].val;
        int sb=(int)sqrt(n);
        if (sb>n)sb=n;
        for (i=1;i<=n;i++)
        {
                Add_sgt(roof[i],roof[i-1],1,m,num[i]);
        }
        memset(bs,INF,sizeof(bs));
        memset(bt,0,sizeof(bt));
        for (i=1;i<=n;i++)
        {
                bs[i/sb]=min(bs[i/sb],i);
                bt[i/sb]=max(bt[i/sb],i);
        }
        int tp=n/sb;
        int res=0;
        for (i=0;i<=tp;i++)
        {
                memset(tarr,0,sizeof(tarr));
                for (j=bs[i];j<=n;j++)
                {
                        bres1[i][j]=bres1[i][j-1]+j-bs[i]-Qry_sum(num[j]);
                        Add_val(num[j]);
                }
        }
        int q;
        scanf("%d",&q);
        res=0;
        int t;
        for (i=0;i<q;i++)
        {
                scanf("%d%d",&x,&y);
                x^=res;y^=res;
                if (abs(x/sb - y/sb)<=0)
                {
                        res=0;
                        for (j=x+1;j<=y;j++)
                        {
                                res+=Qry_tot(x,j-1,num[j]+1,m);
                        }
                        printf("%d\n",res);
                }else
                {
                        res=bres1[x/sb+1][y];
                        for (j=x;j<=bt[x/sb];j++)
                        {
                                res+=Qry_tot(j+1,y,1,num[j]-1);
                        }
                        printf("%d\n",res);
                }
        }
}
时间: 2024-12-10 05:16:21

bzoj 3744: Gty的妹子序列 主席树+分块的相关文章

BZOJ 3744: Gty的妹子序列

3744: Gty的妹子序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1335  Solved: 379[Submit][Status][Discuss] Description 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹

BZOJ 3744 Gty的妹子序列 分块+fenwick

题目大意:强制在线区间无修改逆序对. 思路:看到数据范围发现分块是很显然的.预处理了很多东西,比如说每个块里面的逆序对个数,还有f[i][j]表示从第i块到第j块的逆序对个数.如果仅仅处理到这里的话,后面是不太好处理的.我们还需要一个东西,是每个点对每个块的逆序对个数,并取前缀合优化.否则的话就得用主席树来乱搞,那常数 反正总时间复杂度大概是O(n*sqrt(n)*logn)  强行不到O(n^2) 剩下就是小事了, 比如离散话啥的.. CODE: #include <cmath> #incl

bzoj 3744 Gty的妹子序列 区间逆序对数(在线) 分块

题目链接 题意 给定\(n\)个数,\(q\)个询问,每次询问\([l,r]\)区间内的逆序对数. 强制在线. 思路 参考:http://www.cnblogs.com/candy99/p/6579556.html 离线的话就如上一题bzoj 3289 Mato的文件管理,可以直接用 莫队 搞,在线的话怎么办呢? 分块大法好. 1 预处理出两个信息: \(f[i][j]\):从 第\(i\)块开始位置 到 位置\(j\) 这段区间的逆序对数 \(s[i][j]\):前\(i\)块中\(\leq

BZOJ 3744: Gty的妹子序列 [分块]

传送门 题意:询问区间内逆序对数 感觉这种题都成套路题了 两个预处理$f[i][j]$块i到j的逆序对数,$s[i][j]$前i块$\le j$的有多少个 f我直接处理成到元素j,方便一点 用个树状数组就行了 预处理和查询都带$log$所以还是开根号n比较科学吧 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath>

bzoj3744: Gty的妹子序列 (BIT &amp;&amp; 分块)

强制在线的区间询问逆序对数 如果不是强制在线 就是可以用莫队乱搞啦 强制在线的话 用f[i][j]记录第i块到第j个点之间的逆序对数 用s[i][j]记录前i块中小于等于j的数字个数 离散化一下 BIT用来处理需要暴力的地方即可 下面是代码 1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 #include <cstring> 5 using namespace std; 6 #d

Bzoj 3809: Gty的二逼妹子序列 莫队,分块

3809: Gty的二逼妹子序列 Time Limit: 35 Sec  Memory Limit: 28 MBSubmit: 868  Solved: 234[Submit][Status][Discuss] Description Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题. 对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数. 为了方便,我们规定妹子们的美丽度全都在[1,n]中. 给定一个长度为n(1<=n<=100000)的

【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

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

BZOJ 3720 Gty的妹子树 块状树

题目大意:维护一棵树,每个点有一个权值,提供下列操作: 1.询问某棵子树中有多少个节点的权值大于x 2.修改某个节点的权值 3.增加一个叶子节点 强制在线 传说中的树分块 首先DFS,对于每个节点,如果这个节点的父亲节点所在块未满,就塞进父节点所在块中,否则自成一块,然后与父节点所在的块连边 添加节点同理 然后就按照分块直接搞吧0.0 细节实在是太多了 所以写挂的地方看看本蒟蒻的代码就好了0.0 #include <cmath> #include <cstdio> #include

bzoj 4026 dC Loves Number Theory (主席树+数论+欧拉函数)

题目大意:给你一个序列,求出指定区间的(l<=i<=r) mod 1000777 的值 还复习了欧拉函数以及线性筛逆元 考虑欧拉函数的的性质,(l<=i<=r),等价于 (p[j]是区间内所有出现过的质数) 那么考虑找出区间内所有出现过的质数,这思路和HH的项链是不是很像?? 由于此题强制在线,所以把树状数组替换成了主席树而已 原来我以前写的主席树一直都是错的......还好推出了我原来错误代码的反例 在继承上一个树的信息时,注意不要破坏现在的树 1 #include <cs