BZOJ 3744: Gty的妹子序列

3744: Gty的妹子序列

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1335  Solved: 379
[Submit][Status][Discuss]

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

HINT

Source

By Autumn

[Submit][Status][Discuss]

╮(╯▽╰)╭  Gty的撩妹技能我等蒟蒻就是不能比。

分块+主席树+树状数组 随便搞一发就好了(其实调了好久)。

  1 #include <bits/stdc++.h>
  2
  3 namespace fastRead
  4 {
  5     inline int nextChar(void)
  6     {
  7         static const int siz = 1 << 20;
  8
  9         static char buf[siz];
 10         static char *hd = buf + siz;
 11         static char *tl = buf + siz;
 12
 13         if (hd == tl)
 14             fread(hd = buf, 1, siz, stdin);
 15
 16         return int(*hd++);
 17     }
 18
 19     inline int nextInt(void)
 20     {
 21         register int ret = 0;
 22         register int neg = false;
 23         register int bit = nextChar();
 24
 25         for (; bit < 48; bit = nextChar())
 26             if (bit == ‘-‘)neg ^= true;
 27
 28         for (; bit > 47; bit = nextChar())
 29             ret = ret * 10 + bit - ‘0‘;
 30
 31         return neg ? -ret : ret;
 32     }
 33 }
 34
 35 const int mxn = 50005;
 36
 37 int n, m, h, s[mxn], lastAns = 0;
 38
 39 namespace chairManTree
 40 {
 41     const int siz = 1000005;
 42
 43     int tot;
 44     int cnt[siz];
 45     int lsn[siz];
 46     int rsn[siz];
 47
 48     int root[mxn];
 49
 50     void insert(int &t, int p, int l, int r, int v)
 51     {
 52         t = ++tot;
 53
 54         lsn[t] = lsn[p];
 55         rsn[t] = rsn[p];
 56         cnt[t] = cnt[p] + 1;
 57
 58         if (l != r)
 59         {
 60             int mid = (l + r) >> 1;
 61
 62             if (v <= mid)
 63                 insert(lsn[t], lsn[p], l, mid, v);
 64             else
 65                 insert(rsn[t], rsn[p], mid + 1, r, v);
 66         }
 67     }
 68
 69     int query(int a, int b, int l, int r, int x, int y)
 70     {
 71         if (l == x && r == y)
 72             return cnt[a] - cnt[b];
 73
 74         int mid = (l + r) >> 1;
 75
 76         if (y <= mid)
 77             return query(lsn[a], lsn[b], l, mid, x, y);
 78         else if (x > mid)
 79             return query(rsn[a], rsn[b], mid + 1, r, x, y);
 80         else
 81             return query(lsn[a], lsn[b], l, mid, x, mid) + query(rsn[a], rsn[b], mid + 1, r, mid + 1, y);
 82     }
 83
 84     inline void main(void)
 85     {
 86         for (int i = 1; i <= n; ++i)
 87             insert(root[i], root[i - 1], 1, h, s[i]);
 88     }
 89
 90     inline int query(int l, int r, int k)
 91     {
 92         if (k > 1)
 93             return query(root[r], root[l - 1], 1, h, 1, k - 1);
 94         else
 95             return 0;
 96     }
 97 }
 98
 99 namespace binaryInsertTree
100 {
101     int tree[mxn];
102
103     inline void add(int p, int v)
104     {
105         for (; p <= h; p += p&-p)
106             tree[p] += v;
107     }
108
109     inline int qry(int p)
110     {
111         int ret = 0;
112
113         for (; p >= 1; p -= p&-p)
114             ret += tree[p];
115
116         return ret;
117     }
118
119     inline void init(void)
120     {
121         memset(tree, 0, sizeof(tree));
122     }
123 }
124
125 namespace divideSequence
126 {
127     const int mxt = 255;
128
129     int t, st[mxt], tot, rev[mxt][mxn];
130
131     inline int findStart(int k)
132     {
133         int lt = 1, rt = tot, mid, ans = 0;
134
135         while (lt <= rt)
136         {
137             mid = (lt + rt) >> 1;
138
139             if (st[mid] >= k)
140                 rt = mid - 1, ans = mid;
141             else
142                 lt = mid + 1;
143         }
144
145         return ans;
146     }
147
148     inline void main(void)
149     {
150         t = int(sqrt(n) + 0.5);
151
152         for (int i = 1, j = 1; i <= n; i += t, ++j)
153         {
154             st[j] = i;
155
156             binaryInsertTree::init();
157
158             for (int k = i, sum = 0; k <= n; ++k, ++sum)
159             {
160                 rev[j][k] = rev[j][k - 1];
161                 rev[j][k] += sum - binaryInsertTree::qry(s[k]);
162
163                 binaryInsertTree::add(s[k], 1);
164             }
165
166             tot = j;
167         }
168     }
169 }
170
171 namespace preworkHash
172 {
173     int map[mxn], tot;
174
175     inline int find(int k)
176     {
177         int lt = 1, rt = tot, mid, ans;
178
179         while (lt <= rt)
180         {
181             mid = (lt + rt) >> 1;
182
183             if (map[mid] <= k)
184                 lt = mid + 1, ans = mid;
185             else
186                 rt = mid - 1;
187         }
188
189         return ans;
190     }
191
192     inline void main(void)
193     {
194         for (int i = 1; i <= n; ++i)
195             map[i] = s[i];
196
197         std::sort(map + 1, map + 1 + n);
198
199         for (int i = 1; i <= n; ++i)
200             if (!tot || map[i] != map[tot])
201                 map[++tot] = map[i];
202
203         for (int i = 1; i <= n; ++i)
204             s[i] = find(s[i]);
205
206         h = tot;
207     }
208 }
209
210 inline int solve(int l, int r)
211 {
212     int id = divideSequence::findStart(l), st, ret;
213
214     if (id)
215     {
216         st = divideSequence::st[id];
217         ret = divideSequence::rev[id][r];
218     }
219     else
220         st = r + 1, ret = 0;
221
222     if (st > r)
223         st = r + 1;
224
225     for (int i = l; i < st; ++i)
226         ret += chairManTree::query(st, r, s[i]);
227
228     binaryInsertTree::init();
229
230     for (int i = l, sum = 0; i < st; ++i, ++sum)
231     {
232         ret += sum - binaryInsertTree::qry(s[i]);
233
234         binaryInsertTree::add(s[i], 1);
235     }
236
237     return ret;
238 }
239
240 signed main(void)
241 {
242     n = fastRead::nextInt();
243
244     for (int i = 1; i <= n; ++i)
245         s[i] = fastRead::nextInt();
246
247     preworkHash::main();
248
249     chairManTree::main();
250
251     divideSequence::main();
252
253     m = fastRead::nextInt();
254
255     for (int i = 1; i <= m; ++i)
256     {
257         int l = fastRead::nextInt();
258         int r = fastRead::nextInt();
259
260         l ^= lastAns;
261         r ^= lastAns;
262
263         printf("%d\n", lastAns = solve(l, r));
264     }
265 }

@Author: YouSiki

时间: 2024-12-31 06:35:02

BZOJ 3744: Gty的妹子序列的相关文章

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

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

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的妹子序列 分块+fenwick

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

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的妹子序列 分块+树状数组+主席树

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

bzoj3744 Gty的妹子序列

我是萌萌的传送门 感觉这题还是不错的--虽然其实算是比较水的题= = 首先分块,令f[i][j]表示第i块到第j块的逆序对数,询问的时候直接计算不完整块与完整块以及不完整块之间的逆序对. 不完整块之间的逆序对直接树状数组暴力求,至于不完整块和完整块的逆序对,我是令s[i]表示前i块的权值前缀和,这样单次查询O(1),可以减小一点常数,代价是空间稍微费了点-- 预处理O(nsqrt(n)logn),单次查询O(sqrt(n)logn),空间O(nsqrt(n)),好吧我懒得算如何调节块大小来降低复

BZOJ 3720 Gty的妹子树 树上分块

题目大意:给出一棵树,要求维护:1.求出以x为根节点的子树的严格大于y的数量. 2.将一个节点的权值改变. 3.在一个节点下加一个权值为y的节点. 思路:分块这个东西太神了(别找我分析时间复杂度..树上的分块更神... 首先,分块的原则和正常分块一样,把一棵树分成√n块,每一块不超过√n个,然后所有的时间复杂度降到了O(√n),(这个题还有个排序,所以还有一个log(n)). 如何在树上分块.规定根节点在编号为1的块中,然后做一次深搜,如果遍历到的一个节点的时候当前节点所在的块的数量已经达到最大

BZOJ 3720: Gty的妹子树 [树上size分块]

传送门 题意: 一棵树,询问子树中权值大于$k$的节点个数,修改点权值,插入新点:强制在线 一开始以为询问多少种不同的权值,那道CF的强制在线带修改版,直接吓哭 然后发现看错了这不一道树上分块水题... 用王室联邦分块的话需要维护每一个块$dfs$序最小值和最大值,并且插入操作会破坏原来的性质 不如直接按$size$分块,根节点$size<block$就加入根,否则新建块 $size$分块不能保证块的数量,可以被菊花图卡掉,然而本题没有所以就可以安心的写了 每个块维护排序后的值 查询操作,不完整

【bzoj3744】GTY的妹子序列

大力分块+树状数组+主席树-- #include<bits/stdc++.h> #define N 50005 #define pa pair<int,int> #define fi first #define sc second using namespace std; int n,m,cnt,tot,size,t; int a[N],c[N],num[N],rt[N]; int sum[250][N]; inline int lowbit(int x){return (x&am