[P3759][TJOI2017]不勤劳的图书管理员(分块+树状数组)

题目描述

加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员。他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生 这两本书页数的和的厌烦度。现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置。因为小豆被要求在接下来的m天中至少 要整理一次图书。小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理。

输入输出格式

输入格式:

第一行会有两个数,n,m分别表示有n本书,m天

接下来n行,每行两个数,ai和vi,分别表示第i本书本来应该放在ai的位置,这本书有vi页,保证不会有放置同一个位置的书

接下来m行,每行两个数,xj和yj,表示在第j天的第xj本书会和第yj本书会因为读者阅读交换位置

输出格式:

一共m行,每行一个数,第i行表示前i天不去整理,第i天小豆的厌烦度,因为这个数可能很大,所以将结果模10^9 +7后输出

输入输出样例

输入样例#1:
复制

5 5
1 1
2 2
3 3
4 4
5 5
1 5
1 5
2 4
5 3
1 3

输出样例#1: 复制

42
0
18
28
48

说明

对于20%的数据,1 ≤ ai; xj; yj ≤ n ≤ 5000, m ≤ 5000, vi ≤ 10^5

对于100%的数据,1 ≤ ai; xj; yj ≤ n ≤ 50000, m ≤ 50000, vi ≤ 10^5

不想写或者不会写数据结构的用分块就好,然后有两种写法,一种是对每一块排序,一种是对每块维护一个树状数组。

这样分L和R在同一块,L和R所在的两个不完整的块,L和R跨过的完整的块三种情况讨论即可。

注意!!这题前两种情况一定不能暴力重建块!暴力重建的用时是1200+s,如果只更新变化的部分就只要80+s。

还有一个问题,因为整块标记的复杂度是$O(\frac{n}{S}  \log n)$的(其中S是块的大小),所以S设为$\sqrt{n \log n}$的速度是设为$\sqrt{n}$的两倍。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 typedef long long ll;
 6 #define rep(i,l,r) for (register int i=l; i<=r; i++)
 7 using namespace std;
 8
 9 const ll N=50100,md=1000000007;
10 int n,m,mx,L,R,B,a[N],v[N],sz[N],bl[N],cnt,sum[N],d[300],c[250][N],c1[250][N],ans;
11
12 void add(int c[],int x,int k){ for (; x<=n; x+=x&-x) c[x]=(c[x]+k)%md; }
13 int que(int c[],int x){ ll res=0; for (; x; x-=x&-x) res=(res+c[x])%md; return res; }
14 void add1(int c1[],int x,int k){ for (; x<=n; x+=x&-x) c1[x]=(c1[x]+k)%md; }
15 int que1(int c1[],int x){ ll res=0; for (; x; x-=x&-x) res=(res+c1[x])%md; return res; }
16 int get(int x){ return x>=0 ? x : x+md; }
17
18 void cal(int x,int y,int z){
19     if (a[x]<a[z]) ans=(ans+v[x]+v[z])%md; else ans=(ans-v[x]-v[z]+md+md)%md;
20     if (a[y]<a[z]) ans=(ans+md+md-v[y]-v[z])%md; else ans=(ans+v[y]+v[z])%md;
21 }
22
23 void work(int L,int R){
24     if (L==R) return;
25     if (bl[L]==bl[R]){
26         rep(i,L+1,R-1) cal(L,R,i); swap(a[L],a[R]); swap(v[L],v[R]);
27     }else{
28         rep(i,L+1,(bl[L]-1)*B+sz[bl[L]]) cal(L,R,i);
29         rep(i,(bl[R]-1)*B+1,R-1) cal(L,R,i);
30         swap(a[L],a[R]); swap(v[L],v[R]);
31         sum[bl[L]]=(sum[bl[L]]+md-v[R]+v[L])%md; sum[bl[R]]=(sum[bl[R]]+md-v[L]+v[R])%md;
32         add(c[bl[R]],a[L],-v[L]); add(c[bl[L]],a[R],-v[R]); add1(c1[bl[R]],a[L],-1); add1(c1[bl[L]],a[R],-1);
33         add(c[bl[L]],a[L],v[L]); add(c[bl[R]],a[R],v[R]); add1(c1[bl[L]],a[L],1); add1(c1[bl[R]],a[R],1);
34         rep(i,bl[L]+1,bl[R]-1){
35             ans=get((1ll*ans-(que(c[i],a[R]-1)+1ll*que1(c1[i],a[R]-1)*v[R])%md));
36             ans=get((1ll*ans+(que(c[i],a[L]-1)+1ll*que1(c1[i],a[L]-1)*v[L]))%md);
37             ans=get((1ll*ans-(sum[i]-que(c[i],a[L])+1ll*(sz[i]-que1(c1[i],a[L]))*v[L]))%md);
38             ans=get((1ll*ans+(sum[i]-que(c[i],a[R])+1ll*(sz[i]-que1(c1[i],a[R]))*v[R]))%md);
39         }
40     }
41     if (a[R]<a[L]) ans=(1ll*ans+v[L]+v[R])%md; else ans=get((1ll*ans-(v[L]+v[R]))%md);
42 }
43
44 int main(){
45     freopen("book.in","r",stdin);
46     freopen("book.out","w",stdout);
47     scanf("%d%d",&n,&m); B=(int)sqrt(n*17);
48     rep(i,1,n) scanf("%d%d",&a[i],&v[i]);
49     rep(i,1,n) bl[i]=(i-1)/B+1; mx=(n-1)/B+1;
50     rep(i,1,mx-1) sz[i]=B; sz[mx]=n-(mx-1)*B;
51     rep(i,1,n) add(c[bl[i]],a[i],v[i]),add1(c1[bl[i]],a[i],1),sum[bl[i]]=(sum[bl[i]]+v[i])%md;
52     rep(i,1,n){
53         ans=get((1ll*ans+(i-1-1ll*que1(c1[0],a[i]-1))*v[i]+cnt-que(c[0],a[i]-1))%md);
54         add(c[0],a[i],v[i]); add1(c1[0],a[i],1); cnt=(cnt+v[i])%md;
55     }
56     rep(i,1,m) scanf("%d%d",&L,&R),work(min(L,R),max(L,R)),printf("%d\n",ans);
57     return 0;
58 }

原文地址:https://www.cnblogs.com/HocRiser/p/8459700.html

时间: 2024-08-07 04:52:11

[P3759][TJOI2017]不勤劳的图书管理员(分块+树状数组)的相关文章

【bzoj4889】: [Tjoi2017]不勤劳的图书管理员 分块-BIT

[bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000),每次交换两个数的位置,交换m次(m<=50000) 求每次交换后的序列的杂乱度对1e9+7取模(对于每一对是逆序对的编码会产生两者权值和的杂乱度). 感觉正解是什么奇怪的树套树?蒟蒻只会分块水题.. 先用BIT求一遍初始状态的杂乱度..(不要问我为什么一开始是BIT..因为打暴力正好用到就懒得改了.

洛谷P3759 - [TJOI2017]不勤劳的图书管理员

Portal Description 给出一个\(1..n(n\leq5\times10^4)\)的排列\(\{a_n\}\)和数列\(\{w_n\}(w_i\leq10^5)\),进行\(m(m\leq5\times10^4)\)次操作: 交换\(a_{p_1},a_{p_2}\),并求\(\sum_{i=1}^n \sum_{j=i+1}^n [a_i>a_j](w_{a_i}+w_{a_j})\). Solution 树套树/CDQ分治,想锻炼一下代码能力所以写了树套树. 首先这是一个求逆

P3759 [TJOI2017]不勤劳的图书管理员 [树套树]

树套树是什么啊我不知道/dk 我只知道卡常数w // by Isaunoya #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize( "inline,-fgcse,-fgcse-lm,-fipa-sra,-ftree-pre,-ftree-vrp,-fpeephole2,-ffast-math,-fsched-spec,unroll-

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

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

hdu 5193 分块 树状数组 逆序对

题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除.求每次修改后逆序对的个数. 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个. 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力.查找权值个数时,使用树状数组比较方便.内层通过树状数组维护权值. 每次更新即

[bzoj4889] [Tjoi2017]不勤劳的图书管理员

Description 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置.因为小豆被要求在接下来的m天中至少要整理一次图书.小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理. Input 第一行会有两个数,n,m分别表示有n本书,m天 接下来n行,每行两个数

【BZOJ4167】永远的竹笋采摘 分块+树状数组

[BZOJ4167]永远的竹笋采摘 题解:我们考虑有多少点对(a,b)满足a与b的差值是[a,b]中最小的.以为是随机数据,这样的点对数目可能很少,实测是O(n)级别的,那么我们已知了有这么多可能对答案造成贡献的点对,如何将它们求出来呢? 考虑分块,因为所有数大小在[1,n]中,我们可以对于每个块,预处理出整个块到所有数的最小差值.然后从右往左枚举每一个点,再枚举右面所有的块,如果这个块到当前数的差值比之前的要小,那就暴力进入块中扫一遍.与此同时,我们需要知道是否已经存在这样的点对,被当前的点对

BZOJ 2141 排队 分块+树状数组

题目大意:给定一个序列,m次交换两个数,求初始逆序对数及每次交换后的逆序对数 首先离散化,分块,对于每块建立一个树状数组,保存这个块中的所有元素 然后对于每个询问(x,y) (x<y) 两侧的数是没有影响的,区间(x,y)的数a[i]讨论如下: a[i]<a[x] --ans a[i]>a[x] ++ans a[i]<a[y] ++ans a[i]>a[y] --ans 然后对于块中的树状数组处理,块外的暴力 注意此题元素有重复 亲测可信 RANK5吓尿0.0 为何块套树要比

【XSY2111】Chef and Churus 分块 树状数组

题目描述 有一个长度为\(n\)的数组\(A\)和\(n\)个区间\([l_i,r_i]\),有\(q\)次操作: \(1~x~y\):把\(a_x\)改成\(y\) \(2~x~y\):求第\(l\)个区间到第\(r\)个区间的区间和的和. \(n,q\leq {10}^5,a_i\leq {10}^9\) 题解 分块. 设\(s_i\)为第\(i\)块的所有区间的区间和,\(d_{i,j}\)为第\(i\)块有多少个区间包含了\(j\)这个位置. 修改时修改树状数组和每个区间的区间和.设当前