[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 ...
随机推荐
- MySQL中事物的详解
1. 事物的定义及特性 事务是一组操作数据库的SQL语句组成的工作单元,该工作单元中所有操作要么同时成功,要么同时失败.事物有如下四个特性,ACID简称“酸性”. 1)原子性:工作单元中所有的操作要么 ...
- pycharm界面美化,个人喜欢
进入file-setting选项 界面设置主要是在appearance和editor里面.appearance主要是整个pycharm的主题设置,比如文件管理窗口的颜色,其实就是软件本身的主题设置.我 ...
- CentOS 6.5通过yum安装 MySQL-5.5
1.安装mysql-5.5的yum源 rpm -ivh http://repo.mysql.com/yum/mysql-5.5-community/el/6/x86_64/mysql-communit ...
- 交换机基础配置之跨交换机划分vlan
我们以上面的拓扑图来进行实验 四台pc机都在同一网段 pc1和pc2在同一台交换机上 pc3和pc4在同一台交换机上 现在我们实验的目的就是将pc1和pc3划分到同一vlan pc2和pc4划分到同一 ...
- photoshop入门笔记2:PS箭头的制作
---恢复内容开始--- 1. 首先打开ps软件,在ps里新建一个画布这里就500*500,可以随意. 2.然后在ps软件界面上的工具栏里找到‘直线工具’,如图. 3.选择好工具之后,在ps软 ...
- 宁夏邀请赛F FLOYD
Moving On Firdaws and Fatinah are living in a country with nn cities, numbered from 11 to nn.Each ci ...
- Postgres主备切换
主备查询 主备不会自动切换(即需要实现线上环境主数据库宕掉之后,从数据库能够自动切换为主数据库,需要借用第三方软件,例如heartbeat等) (1)如何查看是primary还是standby 方法1 ...
- Aizu:2170-Marked Ancestor
Marked Ancestor Time limit 8000 ms Memory limit 131072 kB Problem Description You are given a tree T ...
- Spark机器学习之推荐引擎
一. 最小二乘法建立模型 关于最小二乘法矩阵分解,我们可以参阅: 一.矩阵分解模型. 用户对物品的打分行为可以表示成一个评分矩阵A(m*n),表示m个用户对n各物品的打分情况.如下图所示: 其中,A( ...
- Linux下添加桌面快捷方式
这里用Ubuntu下BurpSuite举例 sudo vim /home/user/Desktop/burpsuite.desktop //burpsuite随意起名,系统会系动创建文件 文件写入 # ...