[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 ...
随机推荐
- STL 之 set的应用
关于set Set是STL中的一个容器,特点是其中包含的元素值是唯一的,set根据其底层实现机制分为hash存储和红黑树存储两种方式,这两种结构最本质的区别就是有序和无序,红黑树的存储是有序的而has ...
- 转载:字符串HASH
转载自:Slager_Z 字符串Hash总结 Hash是什么意思呢?某度翻译告诉我们: hash 英[hæʃ] 美[hæʃ]n. 剁碎的食物; #号; 蔬菜肉丁;vt. 把…弄乱; 切碎; 反复推敲; ...
- mongodb多个查询语句
db.getCollection('costitems').find({"created":{"$gte":ISODate("2019-01-02T0 ...
- H5拍照、选择图片上传组件核心
背景 前段时间项目重构,改成SSR的项目,但之前用的图片选择上传组件不支持SSR(server-side-render).遂进行了调研,发现很多的工具.但有的太大,有的使用麻烦,有的不满足使用需求.决 ...
- myql简单语法测试
删除某一行 delete from name1 where agee=10 limit 1; insert into name1(agee,namee)values(10,'wwww'),(10,' ...
- 图解HTTP总结(3)——HTTP报文内的HTTP信息
HTTP通信过程包括从客户端发往服务端的请求及从服务器端返回客户端的响应. 用于HTTP协议交互的信息被称为HTTP报文.客户端的HTTP报文叫做请求报文,服务器端的叫做响应报文.HTTP报文本身是多 ...
- PPT入门学习笔记1:待修改
一直被比人忽悠实在是累了,我可以接受自己的失误,但我接受不了别人一次又一次的坑我! 做PPT的原则是什么? 1.一个目标: "一个PPT只为一类人服务,针对不同的听众制作不同层次内容的PPT ...
- [Codeforces976E]Well played!(贪心)
[不稳定的传送门] Solution 首先可以证明,hp翻倍的操作一定是在同一个生物上最优 Code #include <cstdio> #include <algorithm> ...
- mac上MySQLdb问题解决
早上有个同学问题python访问mysql的问题,之前的写得脚步突然不能运行了,找了很多文章总算解决问题了O(∩_∩)O哈哈~,希望下次不要浪费这么多时间搞这么坑的问题了. mac上MySQLdb ...
- Win7更换锁屏和开机画面
技术交流群:233513714 每次开机被Windows千年不变的开机画面和锁屏画面丑到的小伙伴们可以看过来,通过简单的几步就可以改掉系统默认的开机画面. 1.首先Windows+r键输入regedi ...