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

Posted HocRiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 }

 

以上是关于[P3759][TJOI2017]不勤劳的图书管理员(分块+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

题解[TJOI2017]不勤劳的图书管理员

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

4889: [Tjoi2017]不勤劳的图书管理员 树套树

BZOJ4889 & 洛谷3759:[TJOI2017]不勤劳的图书管理员——题解