[TJOI2017][bzoj4889] 不勤劳的图书管理员 [线段树套线段树]
题面
思路
考虑两本书的位置交换对答案的贡献:
(为了方便描述,用“左边那本”和“右边那本”称呼两本我们要交换的书,“中间那本”是我们的讨论对象)
对于位置在两本书中间的书,分情况讨论:
情况1,这本书的权值在两本书中间
如果左边的书比右边的书大(也就是交换的两本书本来是逆序对,交换后变成顺序对),那么这本中间的书对答案的改变为$-(2\ast mid + left + right)$
如果左边比右边小(原来是顺序,交换后变成逆序),中间的这本书贡献为$+(2\ast mid + left + right)$
情况2,这本书的权值比两本书都要小
此时,左边的那本书和中间这本一定构成逆序对,右边那本和中间这本一定构成顺序对
这样,交换以后原来由左边的书做出的贡献就变成了右边的书的,改变为$+(right-left)$
情况3,这本书的权值比两本书都要大
同情况2,此时改变为$+(left-right)$
讨论到此结束,我们发现我们只需要动态维护区间中某个权值范围内的数的查询即可
这是树套树模板问题,线段树套线段树即可解决,采取外层位置内层权值的解决方案
注意线段树套线段树的空间复杂度是$O(n\log^2n)$的,需要在底层采取动态开点的内存分配方法
Code
// luogu-judger-enable-o2
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cassert>
#include<queue>
#define ll long long
#define MOD 1000000007
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m;
struct ele{
int num;ll val;
ele(){num=val=0;}
ele(int nn,ll vv){num=nn,val=vv;}
inline ele operator +(const ele &b){return ele(num+b.num,val+b.val);}
};
namespace ctrl{
int cnt;queue<int>q;
int newnode(){
if(!q.empty()){int tmp=q.front();q.pop();return tmp;}
else return ++cnt;
}
void del(int num){
q.push(num);
}
}
//inner
namespace seg{
ll a[8000010];int num[8000010],ch[8000010][2];
int pos,f,ql,qr;ll val;
void insert(int &cur,const int l,const int r){
if(!cur) cur=ctrl::newnode();
num[cur]+=f;(a[cur]+=val*f)%=MOD;
assert((num[cur]==0)==(a[cur]==0));
if(l==r){
if(!num[cur]&&!a[cur]){
ch[cur][0]=ch[cur][1]=0;
ctrl::del(cur);
cur=0;
}
return;
}
int mid=(l+r)>>1;
if(mid>=pos) insert(ch[cur][0],l,mid);
else insert(ch[cur][1],mid+1,r);
if(!num[cur]&&!a[cur]){
ch[cur][0]=ch[cur][1]=0;
ctrl::del(cur);
cur=0;
}
}
ele query(const int cur,const int l,const int r){
if(!cur) return ele(0,0);
if(l>=ql&&r<=qr) return ele(num[cur],a[cur]);
const int mid=(l+r)>>1;ele re;
if(mid>=ql) re=re+query(ch[cur][0],l,mid);
if(mid<qr) re=re+query(ch[cur][1],mid+1,r);
return re;
}
}
//outer
namespace SEG{
int root[400010];
int pos,val,page,f,ql,qr,qx,qy;
void insert(const int l,const int r,const int num){
seg::val=page;seg::pos=val;seg::f=f;
seg::insert(root[num],1,n);
if(l==r) return;
int mid=(l+r)>>1;
if(mid>=pos) insert(l,mid,num<<1);
else insert(mid+1,r,num<<1|1);
}
ele query(const int l,const int r,const int num){
if(l>=ql&&r<=qr){
seg::ql=qx;seg::qr=qy;
return seg::query(root[num],1,n);
}
const int mid=(l+r)>>1;ele re;
if(mid>=ql) re=re+query(l,mid,num<<1);
if(mid<qr) re=re+query(mid+1,r,num<<1|1);
re.val%=MOD;
return re;
}
}
int rk[100010];ll ans,v[100010];
int main(){
using namespace SEG;
n=read();m=read();int i,t1,t2,minn,maxn;ele tmp;
for(i=1;i<=n;i++){
rk[i]=read();v[i]=read();
ql=1;qr=i-1;qx=rk[i]+1;qy=n;
if(qr>=ql&&qy>=qx){
tmp=query(1,n,1);
(ans+=(tmp.val+(ll)tmp.num*v[i])%MOD)%=MOD;
}
pos=i;val=rk[i];page=v[i];f=1;
insert(1,n,1);
}
for(i=1;i<=m;i++){
t1=read();t2=read();
if(t1>t2) swap(t1,t2);
if(t1==t2){printf("%lld\n",ans);continue;}
minn=min(rk[t1],rk[t2]);
maxn=max(rk[t1],rk[t2]);
(ans+=((minn==rk[t1])?1:-1)*(v[t1]+v[t2]))%=MOD;
ql=t1;qr=t2;qx=minn+1,qy=maxn-1;
if(qy>=qx){
tmp=query(1,n,1);
(ans+=((minn==rk[t1])?1:-1)*((tmp.val*2ll+(v[t1]+v[t2])*(ll)tmp.num)%MOD))%=MOD;
}
ql=t1;qr=t2;qx=1;qy=minn-1;
if(qy>=qx){
tmp=query(1,n,1);
(ans+=(ll)tmp.num*(v[t2]-v[t1])%MOD)%=MOD;
}
ql=t1;qr=t2;qx=maxn+1,qy=n;
if(qy>=qx){
tmp=query(1,n,1);
(ans+=(ll)tmp.num*(v[t1]-v[t2])%MOD)%=MOD;
}
if(ans<0) ans+=MOD;
pos=t1;val=rk[t1];page=v[t1];f=-1;
insert(1,n,1);
pos=t2;val=rk[t2];page=v[t2];f=-1;
insert(1,n,1);
swap(rk[t1],rk[t2]);swap(v[t1],v[t2]);
pos=t1;val=rk[t1];page=v[t1];f=1;
insert(1,n,1);
pos=t2;val=rk[t2];page=v[t2];f=1;
insert(1,n,1);
printf("%lld\n",ans);
}
}
[TJOI2017][bzoj4889] 不勤劳的图书管理员 [线段树套线段树]的更多相关文章
- 【loj2639】[Tjoi2017]不勤劳的图书管理员
#2639. 「TJOI2017」不勤劳的图书管理员 题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产 ...
- 【bzoj4889】: [Tjoi2017]不勤劳的图书管理员 分块-BIT
[bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000 ...
- 【BZOJ4889】[Tjoi2017]不勤劳的图书管理员 分块+树状数组
[BZOJ4889][Tjoi2017]不勤劳的图书管理员 题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让 ...
- 【BZOJ4889】不勤劳的图书管理员(树套树)
[BZOJ4889]不勤劳的图书管理员(树套树) 题面 又是权限题,烦死了 洛谷真好 题解 分开考虑每一次交换产生的贡献. 假设交换\((x,y)\) 检查\(x\)与\(y\)对于区间\([x+1, ...
- 洛谷P3759 - [TJOI2017]不勤劳的图书管理员
Portal Description 给出一个\(1..n(n\leq5\times10^4)\)的排列\(\{a_n\}\)和数列\(\{w_n\}(w_i\leq10^5)\),进行\(m(m\l ...
- 【算法】分块——教主的魔法&不勤劳的图书管理员
由不勤劳的图书管理员带入了分块的坑,深深地被其暴力与优雅所征服.分块的实质就是将暴力块状封装起来,一整块的部分就一整块处理,零碎的部分就怎么暴力怎么来.因为分块大小的原因,限制了零碎部分数据的数量级, ...
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ...
- [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】
题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...
- ZJOI 2017 树状数组(线段树套线段树)
题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r ...
随机推荐
- python基础回顾笔记
1.知道了什么是编程语言 2.知道了python.C#.Java都是语言的种类 3.python:有很多种 cpython.pypy.jpython... 4.python的执行方式有两种: 解释器 ...
- MySQL优化总结-查询总条数
1.COUNT(*)和COUNT(COL) COUNT(*)通常是对主键进行索引扫描,而COUNT(COL)就不一定了,另外前者是统计表中的所有符合的纪录总数,而后者是计算表中所有符合的COL的纪录数 ...
- 准备篇(三)Makefile
Makefile 也是蛮多的, 嵌入式的Makefile也是很重要的,所以单独开一个分支.
- Git使用简单总结--源自廖雪峰网站
创建版本库git add加入到暂存区git commit -m" "加入到分支 时光机穿梭git satus查看仓库的当前状态git diff file 查看修改内容 版本回退HE ...
- 010---Django的模型层(2)
确定模型关系: ''' Publish ---- Book 多对一:一个出版社对应多本书,在多的那张表添加关联字段 Book ---- Author 多对多:一个书对应多个作者,多个作者对应一本书 会 ...
- java8之list集合中取出某一属性的方法
上代码 List<User> list = new ArrayList<User>(); User user1 = new User("第一位"," ...
- 浅谈XX系统跨平台迁移(测试环境)
一 概述 XX系统目前运行在XX-A的云平台上,计划将其迁移至XX-B的云平台. XX系统是java开发,中间组件涉及nginx+keepalived实现各个业务系统之间的高可用,kafka,zook ...
- 15、python之导入模块
一.什么是模块? 模块本质是一个py文件,我们可以通过关键字import将py文件对象导入到当前名称空间. 二.导入模块 1.import module 2.from module import ob ...
- 大话卷积神经网络(CNN)
这几年深度学习快速发展,在图像识别.语音识别.物体识别等各种场景上取得了巨大的成功,例如AlphaGo击败世界围棋冠军,iPhone X内置了人脸识别解锁功能等等,很多AI产品在世界上引起了很大的 ...
- [bzoj1552][Cerc2007]robotic sort&&[bzoj3506][Cqoi2014]排序机械臂
非常垃圾的一道平衡树,结果被日了一天.很难受嗷嗷嗷 首先不得不说网上的题解让我这个本来就不熟悉平衡树的彩笔很难受——并不好理解. 还好Sinogi大佬非常的神,一眼就切掉了,而且用更加美妙的解法. 题 ...