[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 ...
随机推荐
- js复习,预编译
注意:函数声明整体提升.变量 声明提升 1.imply global 暗示全局变量:即任何变量,如果变量未声明就赋值,此变量就为全局对象所有 ==> eg: a = 122;==> e ...
- php-5.6.26源代码 - opcode处理器,“乘法opcode”处理器
// opcode处理器 - 运算符怎么执行: “*” 乘法opcode处理器 static int ZEND_FASTCALL ZEND_MUL_SPEC_CONST_CONST_HANDLER(Z ...
- php - empty() is_null() isset()的区别
empty():当变量存在,并且是一个非空非零的值时,返回 FALSE,否则返回 TRUE. is_null():如果指定变量为 NULL,则返回 TRUE,否则返回 FALSE. isset():如 ...
- 在CentOS VPS上通过SSH安装 MySQL
输入 yum install mysql-server 按Y继续 安装完成,设置开机启动Mysql,输入 chkconfig --levels 235 mysqld on 然后启动tomcat,输入s ...
- 带密匙的php加密解密示例分享
<?phpheader("content-type:text/html;charset=utf-8");$id = "http://www.jb51.net&quo ...
- 图解HTTP总结(5)——与HTTP协作的Web服务器
一台 Web 服务器可搭建多个独立域名的 Web 网站, 也可作为通信路径上的中转服务器提升传输效率. 用单台虚拟主机实现多个域名 HTTP/1.1 规范允许一台 HTTP 服务器搭建多个 Web 站 ...
- Apache服务配置
Apache 1.安装Apache服务 第1步:把光盘设备中的系统镜像挂载到/media/cdrom目录. [root@zhangjh ~]# mkdir -p /media/cdrom/ [root ...
- Android 数据库中的数据给到ListView
前言:因为之前学的都是用一个自己定义的类,完成将某一个bean中的数据直接获取,而实际中通常是通过数据库来得到的,总之,最终就是要得到数据.提一下最重要的东西,我把它叫做代理,如同一个校园代理,没有他 ...
- PHP.35-TP框架商城应用实例-后台11-商品分类-删除分类(2种方法)、添加、修改
删除分类 删除一个分类的同时,其所有子分类都删除 在控制器CategoryCtroller.class.php中添加删除函数(delete) 在分类模型中添加钩子函数_before_delete()[ ...
- 16,Flask-Migrate
终于到了Flask-Migrate,之前在学习Flask-SQLAlchemy的时候,Flask支持 makemigration / migrate 吗? 答案在这里该诉你,如果你同时拥有两个三方组件 ...