题目描述(转自洛谷)

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

输入

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

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

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

n、m<=50000

输出

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

样例输入

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

样例输出

42
0
18
28
48


题解

树状数组+分块+二分

一开始看到n、m<=50000写了个区间线段树套权值线段树,结果写了垃圾回收却仍然MLE+RE(也许区间线段树套SBT可能不会MLE或RE,但TLE的事也不好说)

所以不能过分相信nlog^2n数据结构,分块才是王道。

那么本题就和 bzoj3343 相似。

先用树状数组预处理出一开始的答案(正着扫一遍,反过来再扫一遍)。

然后考虑:交换两个数,只对它们中间的数产生影响。所以只需要统计出它们中间有多少个比x大的,比x小的,比y大的,比y小的。

考虑它们原来对答案的贡献,和交换后对答案的贡献,把ans加加减减就好了。

我们可以分块实现这个过程,对于每个块把该块的数排序,并维护前缀和。查询时,对于整块可以二分查找,零碎的部分暴力完成。

最后再判断x和y是否会产生逆序对,并更新答案即可。

注意特判x和y在同一个块内的情况。

另外,本题的ans不用在计算的过程中取模,直接使用long long类型记录,最后输出时取个模就行了。

时间复杂度$O(n\sqrt n\log n)$

#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 50010
using namespace std;
typedef long long ll;
struct data
{
int p;
ll w;
bool operator<(const data a)const {return p < a.p;}
}a[N];
struct block
{
data val[250];
int lp , rp;
ll sum[250];
void build()
{
int i;
for(i = 1 ; i <= rp - lp + 1 ; i ++ ) val[i] = a[i + lp - 1];
sort(val + 1 , val + rp - lp + 2);
for(i = 1 ; i <= rp - lp + 1 ; i ++ ) sum[i] = sum[i - 1] + val[i].w;
}
ll qsmall(int pos)
{
int l = 1 , r = rp - lp + 1 , mid , ans = l - 1;
while(l <= r)
{
mid = (l + r) >> 1;
if(val[mid] < a[pos]) ans = mid , l = mid + 1;
else r = mid - 1;
}
return ans * a[pos].w + sum[ans];
}
ll qbig(int pos)
{
int l = 1 , r = rp - lp + 1 , mid , ans = r + 1;
while(l <= r)
{
mid = (l + r) >> 1;
if(a[pos] < val[mid]) ans = mid , r = mid - 1;
else l = mid + 1;
}
return (rp - lp - ans + 2) * a[pos].w + sum[rp - lp + 1] - sum[ans - 1];
}
}b[250];
int bl[N] , f[N] , g[N] , n;
void add1(int x , ll a) {int i; for(i = x ; i ; i -= i & -i) f[i] += a;}
ll query1(int x) {int i; ll ans = 0; for(i = x ; i <= n ; i += i & -i) ans += f[i]; return ans;}
void add2(int x , ll a) {int i; for(i = x ; i <= n ; i += i & -i) g[i] += a;}
ll query2(int x) {int i; ll ans = 0; for(i = x ; i ; i -= i & -i) ans += g[i]; return ans;}
int main()
{
int m , i , si , x , y;
ll ans = 0 , t1 , t2 , t3 , t4;
scanf("%d%d" , &n , &m) , si = (int)sqrt(n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d%lld" , &a[i].p , &a[i].w) , bl[i] = (i - 1) / si + 1;
for(i = 1 ; i <= bl[n] ; i ++ ) b[i].lp = (i - 1) * si + 1 , b[i].rp = min(i * si , n) , b[i].build();
for(i = 1 ; i <= n ; i ++ ) ans += query1(a[i].p + 1) , add1(a[i].p , a[i].w);
for(i = n ; i >= 1 ; i -- ) ans += query2(a[i].p - 1) , add2(a[i].p , a[i].w);
while(m -- )
{
scanf("%d%d" , &x , &y);
if(x == y) {printf("%lld\n" , ans % 1000000007); continue;}
if(x > y) swap(x , y);
t1 = t2 = t3 = t4 = 0;
if(y - x > 1)
{
if(bl[x] == bl[y])
for(i = x + 1 ; i < y ; i ++ )
t1 += (a[i] < a[x]) * (a[i].w + a[x].w), t2 += (a[x] < a[i]) * (a[i].w + a[x].w) , t3 += (a[i] < a[y]) * (a[i].w + a[y].w) , t4 += (a[y] < a[i]) * (a[i].w + a[y].w);
else
{
for(i = bl[x] + 1 ; i < bl[y] ; i ++ )
t1 += b[i].qsmall(x) , t2 += b[i].qbig(x) , t3 += b[i].qsmall(y) , t4 += b[i].qbig(y);
for(i = x + 1 ; i <= b[bl[x]].rp ; i ++ )
t1 += (a[i] < a[x]) * (a[i].w + a[x].w), t2 += (a[x] < a[i]) * (a[i].w + a[x].w) , t3 += (a[i] < a[y]) * (a[i].w + a[y].w) , t4 += (a[y] < a[i]) * (a[i].w + a[y].w);
for(i = b[bl[y]].lp ; i < y ; i ++ )
t1 += (a[i] < a[x]) * (a[i].w + a[x].w), t2 += (a[x] < a[i]) * (a[i].w + a[x].w) , t3 += (a[i] < a[y]) * (a[i].w + a[y].w) , t4 += (a[y] < a[i]) * (a[i].w + a[y].w);
}
ans = ans - t1 + t2 + t3 - t4;
}
if(a[x] < a[y]) ans += a[x].w + a[y].w;
else ans -= a[x].w + a[y].w;
printf("%lld\n" , ans % 1000000007);
swap(a[x] , a[y]);
b[bl[x]].build() , b[bl[y]].build();
}
return 0;
}

【bzoj4889】[Tjoi2017]不勤劳的图书管理员 树状数组+分块+二分的更多相关文章

  1. luogu3759 不勤劳的图书管理员 (树状数组套线段树)

    交换的话,只有它们中间的书会对答案产生影响 树状数组记位置,套线段树记书的编号 它对应的页数和书的个数 然后就是减掉中间那些原来是逆序对的,再把交换以后是逆序对的加上 别忘了考虑这两个自己交换以后是不 ...

  2. bzoj4889: [Tjoi2017]不勤劳的图书管理员(树套树)

    传送门 据说正解线段树套平衡树 然而网上参考(抄)了一个树状数组套动态开点线段树的 思路比较清楚,看代码应该就明白了 //minamoto #include<iostream> #incl ...

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

    Description 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被 ...

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

    国际惯例的题面(Bzoj没有,洛谷找的):动态加权逆序对,一眼树套树.256MB内存,5e4范围,不虚不虚.首先把交换改成两个插入和两个删除.考虑插入和删除的贡献,就是统计前面比这个值大的数的数值和, ...

  5. LUOGU P3759 [TJOI2017]不勤劳的图书管理员(树套树)

    传送门 解题思路 和以前做过的一道题有点像,就是区间逆序对之类的问题,用的是\(BIT\)套权值线段树,交换时讨论一下计算答案..跑的不如暴力快.. 代码 #include<iostream&g ...

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

    树套树是什么啊我不知道/dk 我只知道卡常数w // by Isaunoya #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC o ...

  7. 【BZOJ4889】[Tjoi2017]不勤劳的图书管理员 分块+树状数组

    [BZOJ4889][Tjoi2017]不勤劳的图书管理员 题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让 ...

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

    [bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000 ...

  9. 【BZOJ4889】不勤劳的图书管理员(树套树)

    [BZOJ4889]不勤劳的图书管理员(树套树) 题面 又是权限题,烦死了 洛谷真好 题解 分开考虑每一次交换产生的贡献. 假设交换\((x,y)\) 检查\(x\)与\(y\)对于区间\([x+1, ...

随机推荐

  1. uvm_base——打好你的基础

    uvm_base 是个很有意思的文件,这是UVM很巧妙的设计,将所有在base中包含的文件都包含在uvm_base.svh, 这样很方便管理各个文件直接的关系,而且还可以看出一些我之前没看过的东西,比 ...

  2. FusionCharts3.2.1 参数的详细说明和功能特性

    功能特性animation                    是否动画显示数据,默认为1(True)showNames                 是否显示横向坐标轴(x轴)标签名称rotat ...

  3. mysql ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")

    解决方案如下:

  4. RLock(递归锁)

    import threading, time def run1(): print("grab the first part data") lock.acquire()#进入大门后的 ...

  5. react native 在window 7上配置开发环境-Andorid

    参照官方配置:https://facebook.github.io/react-native/docs/getting-started.html 因为在配置的过程中遇到很多问题,在此记录一下. 1.j ...

  6. Bootstrap 表格2

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  7. AOP日志组件 多次获取post参数

    AOP日志组件 多次获取post参数 需求:新增接口日志组件.通过拦截器对接口URL进行拦截处理,然后将接口post请求的参数与结果,写入日志表. 问题:POST方法的参数是存储在request.ge ...

  8. 当数据量很少的时候,tableview会显示多余的cell--iOS开发系列---项目中成长的知识二

    当数据量很少的时候,tableview会显示很多的cell,而且是空白的,这样很不美观 所以使用下面的方法可以去掉多余的底部的cell 原理是:设置footerView为frame 是 CGRectZ ...

  9. static静态变量的用法

    一,static全局变量 当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量.静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始 ...

  10. tkinter学习-文本框

    阅读目录 Entry 输入框 Text 文本框 Entry: 说明:输入控件,用于显示简单的文本内容 属性:在输入框中用代码添加和删除内容,同样也是用insert()和delete()方法 from ...