【bzoj4889】[Tjoi2017]不勤劳的图书管理员 树状数组+分块+二分
题目描述(转自洛谷)
加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员。他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度。现在有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]不勤劳的图书管理员 树状数组+分块+二分的更多相关文章
- luogu3759 不勤劳的图书管理员 (树状数组套线段树)
交换的话,只有它们中间的书会对答案产生影响 树状数组记位置,套线段树记书的编号 它对应的页数和书的个数 然后就是减掉中间那些原来是逆序对的,再把交换以后是逆序对的加上 别忘了考虑这两个自己交换以后是不 ...
- bzoj4889: [Tjoi2017]不勤劳的图书管理员(树套树)
传送门 据说正解线段树套平衡树 然而网上参考(抄)了一个树状数组套动态开点线段树的 思路比较清楚,看代码应该就明白了 //minamoto #include<iostream> #incl ...
- [bzoj4889] [Tjoi2017]不勤劳的图书管理员
Description 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被 ...
- 4889: [Tjoi2017]不勤劳的图书管理员 树套树
国际惯例的题面(Bzoj没有,洛谷找的):动态加权逆序对,一眼树套树.256MB内存,5e4范围,不虚不虚.首先把交换改成两个插入和两个删除.考虑插入和删除的贡献,就是统计前面比这个值大的数的数值和, ...
- LUOGU P3759 [TJOI2017]不勤劳的图书管理员(树套树)
传送门 解题思路 和以前做过的一道题有点像,就是区间逆序对之类的问题,用的是\(BIT\)套权值线段树,交换时讨论一下计算答案..跑的不如暴力快.. 代码 #include<iostream&g ...
- P3759 [TJOI2017]不勤劳的图书管理员 [树套树]
树套树是什么啊我不知道/dk 我只知道卡常数w // by Isaunoya #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC o ...
- 【BZOJ4889】[Tjoi2017]不勤劳的图书管理员 分块+树状数组
[BZOJ4889][Tjoi2017]不勤劳的图书管理员 题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让 ...
- 【bzoj4889】: [Tjoi2017]不勤劳的图书管理员 分块-BIT
[bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000 ...
- 【BZOJ4889】不勤劳的图书管理员(树套树)
[BZOJ4889]不勤劳的图书管理员(树套树) 题面 又是权限题,烦死了 洛谷真好 题解 分开考虑每一次交换产生的贡献. 假设交换\((x,y)\) 检查\(x\)与\(y\)对于区间\([x+1, ...
随机推荐
- UIView和Masonry实现动画效果
Masonry 实现动画效果如下: //button点击方法 - (void)clickedButton { static BOOL isMove; //默认是NO Weakify(weakSelf) ...
- 安卓ListView基础应用
listview简单描述 主页面: package com.example.listview; import com.lidroid.xutils.ViewUtils; import com.lidr ...
- mount_cd9660:/dev/acd0: Input/output error
mount -t cd9660 /dev/acd0 /cdrom g_vfs_done():acd0[READ(offset32768, length=204]error =5 mount_cd966 ...
- (三)mybatis之对Hibernate初了解
前言:为什么会写Hibernate呢?因为HIbernate跟Mybatis一样,是以ORM模型为核心思想的,但是这两者有相似的地方也有差异的地方.通过这两种框架的比对,可以对mybatis有着更深的 ...
- Exception in thread "main" java.lang.NoSuchMethodError: org.apache.http.entity.ContentType.withCharset(Ljava/lang/String;)Lorg/apache/http/entity/ContentType;
解决方案是:第一点先检查一下使用的包是否冲突,是否是版本号一致.第二点是增加一个包 忙活了好久才解决了这个异常,小小的激动一下啊啊
- GUI进化--数据与界面分离
http://blog.csdn.net/doon/article/details/5946862 1.何谓数据和界面分离? GUI,即Graphic User Interface,人机交换界面.连接 ...
- ssh的server安装和安装指定版本的软件的方法
ssh程序分为有客户端程序openssh-client和服务端程序openssh-server.如果需要ssh登陆到别的电脑,需要安装openssh-client,该程序ubuntu是默认安装的.而如 ...
- Alfred的配置和使用
http://www.jianshu.com/p/f77ad047f7b0 Alfred:mac上的神兵利器,提升工作效率*n,快捷键:option + 空格.鉴于是看了池老师的<人生元编程 ...
- cdlinux
xset q xset s 6000 xset -dpms ntpdate time.nist.gov date
- activiti整合开发实例总结
参考手册:http://www.mossle.com/docs/activiti/ 一.applicationContext.xml中引入activiti相关配置的xml文件 <!-- begi ...