[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后输出
输入输出样例
说明
对于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 }