bzoj4889 [TJOI2017]不勤劳的图书管理员

本文介绍了一种解决图书管理员因图书乱序而产生的厌烦度计算问题的方法。通过使用线段树数据结构来高效地处理图书位置变化,并计算任意时刻的厌烦度总和,实现了快速响应图书位置变动的需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.elijahqi.win/archives/3142
题目描述

加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员。他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度。现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置。因为小豆被要求在接下来的m天中至少要整理一次图书。小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理。

输入输出格式

输入格式:

第一行会有两个数,n,m分别表示有n本书,m天

接下来n行,每行两个数,ai和vi,分别表示第i本书本来应该放在ai的位置,这本书有vi页,保证不会有放置同一个位置的书

接下来m行,每行两个数,xj和yj,表示在第j天的第xj本书会和第yj本书会因为读者阅读交换位置

输出格式:

一共m行,每行一个数,第i行表示前i天不去整理,第i天小豆的厌烦度,因为这个数可能很大,所以将结果模10^9 +7后输出

输入输出样例

输入样例#1: 复制

5 5
1 1
2 2
3 3
4 4
5 5
1 5
1 5
2 4
5 3
1 3
输出样例#1: 复制

42
0
18
28
48
说明

对于20%的数据,1 ≤ ai; xj; yj ≤ n ≤ 5000, m ≤ 5000, vi ≤ 10^5

对于100%的数据,1 ≤ ai; xj; yj ≤ n ≤ 50000, m ≤ 50000, vi ≤ 10^5

求带权的逆序对 每次会交换 询问逆序对之和

逆序对只和相互之间a的大小有关

考虑针对每个i,j维护一维 每个a[i],a[j]再维护一维

由于每次交换i,j只会影响中间的答案所以我就查下中间

比a[i]大的数字的个数 数字的和

比a[i]小的数字的个数 数字的和

比a[j]大的数字的个数 数字的和

比a[j]小的数字的个数 数字的和

然后思考一下 加加减减获得这次的答案即可

由于内存限制比较小 中间的那层权值线段树需要回收内存

空间:nlog(n)^2时间:nlog(n)^2

注意存在x,y相同的情况 就不能删除两次再加入两次 注意细节..

#include<queue>
#include<cstdio>
#include<cctype>
#define lc (x<<1)
#define rc (x<<1|1)
#include<algorithm>
#define ll long long
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int mod=1e9+7;
const int N=5e4+10;
struct node{
    int size,sum,left,right;
}tree[N*16*16];
queue<int>q;int num,n,m,pos1[N],pos2[N],ans1,ans2,ans,rt[N<<2];
inline int nd(){static int x;
    if(!q.empty()) {x=q.front();q.pop();return x;}return ++num;
}
inline void rec(int &x){
    q.push(x);tree[x].left=tree[x].right=tree[x].sum=tree[x].size=0;x=0;
}
inline void update(int x){
    int l=tree[x].left,r=tree[x].right;tree[x].sum=tree[x].size=0;
    if (l) tree[x].sum=tree[l].sum,tree[x].size=tree[l].size;
    if (r) tree[x].sum+=tree[r].sum,tree[x].size+=tree[r].size;
}
inline void inc(int &x,int v){x=x+v>=mod?x+v-mod:x+v;}
inline void dec(int &x,int v){x=x-v<0?x-v+mod:x-v;}
inline void add(int &x,int l,int r,int p,int v,int t){
    if (!x) x=nd();tree[x].size+=t;if (v>0)inc(tree[x].sum,v);else dec(tree[x].sum,-v);
    if (l==r) {if (!tree[x].size) rec(x);return;}int mid=l+r>>1;
    if (p<=mid) add(tree[x].left,l,mid,p,v,t);else add(tree[x].right,mid+1,r,p,v,t);
    if (!tree[x].size) rec(x);
}
inline void insert1(int x,int l,int r,int p,int p1,int v,int t){
    add(rt[x],1,n,p1,v,t);if (l==r) return;int mid=l+r>>1;
    if (p<=mid) insert1(lc,l,mid,p,p1,v,t);else insert1(rc,mid+1,r,p,p1,v,t);
}
inline void qrp(int x,int l,int r,int p){
    if (!x) return;if(1<=l&&p>r) {inc(ans1,tree[x].size);inc(ans2,tree[x].sum);return;}
    int mid=l+r>>1;if (p<=mid) {qrp(tree[x].left,l,mid,p);return;}
    qrp(tree[x].left,l,mid,p);qrp(tree[x].right,mid+1,r,p);
}
inline void queryp(int x,int l,int r,int l1,int r1,int p){
    if (l1<=l&&r1>=r){qrp(rt[x],1,n,p);return;}int mid=l+r>>1;
    if (l1<=mid) queryp(lc,l,mid,l1,r1,p);if(r1>mid) queryp(rc,mid+1,r,l1,r1,p);
}
inline void qrs(int x,int l,int r,int p){
    if (!x) return;if(p<l&&r<=n) {inc(ans1,tree[x].size);inc(ans2,tree[x].sum);return;}
    int mid=l+r>>1;if (p>mid) {qrs(tree[x].right,mid+1,r,p);return;}
    qrs(tree[x].left,l,mid,p);qrs(tree[x].right,mid+1,r,p);
}
inline void querys(int x,int l,int r,int l1,int r1,int p){
    if (l1<=l&&r1>=r) {qrs(rt[x],1,n,p);return;}int mid=l+r>>1;
    if (l1<=mid) querys(lc,l,mid,l1,r1,p);if (r1>mid) querys(rc,mid+1,r,l1,r1,p);
}
int main(){
//  freopen("bzoj4889.in","r",stdin);
//  freopen("bzoj4889.out","w",stdout);
    n=read();m=read();
    for (int i=1;i<=n;++i){static int x,v;
        x=read();v=read();pos1[i]=x;pos2[i]=v;insert1(1,1,n,i,x,v,1);ans1=0;ans2=0;
        if (i==1) continue;querys(1,1,n,1,i-1,x);inc(ans,(ll)ans1*v%mod);inc(ans,ans2);
    }
    for (int i=1;i<=m;++i){static int x,y;
        x=read();y=read();if (x>y) swap(x,y);if (x==y) {printf("%d\n",ans);continue;}
        if(pos1[x]>pos1[y]) dec(ans,pos2[x]+pos2[y]);else if (pos1[x]<pos1[y]) inc(ans,pos2[x]+pos2[y]);
        if (y-x<=1){
            insert1(1,1,n,x,pos1[x],-pos2[x],-1);insert1(1,1,n,y,pos1[y],-pos2[y],-1);
            swap(pos2[x],pos2[y]);swap(pos1[x],pos1[y]);
            insert1(1,1,n,x,pos1[x],pos2[x],1);insert1(1,1,n,y,pos1[y],pos2[y],1);
            printf("%d\n",ans);
            continue;
        }
        ans1=0;ans2=0;querys(1,1,n,x+1,y-1,pos1[x]);inc(ans,ans2);inc(ans,(ll)ans1*pos2[x]%mod);
        ans1=0;ans2=0;queryp(1,1,n,x+1,y-1,pos1[x]);dec(ans,ans2);dec(ans,(ll)ans1*pos2[x]%mod);
        ans1=0;ans2=0;queryp(1,1,n,x+1,y-1,pos1[y]);inc(ans,ans2);inc(ans,(ll)ans1*pos2[y]%mod);
        ans1=0;ans2=0;querys(1,1,n,x+1,y-1,pos1[y]);dec(ans,ans2);dec(ans,(ll)ans1*pos2[y]%mod);
        insert1(1,1,n,x,pos1[x],-pos2[x],-1);insert1(1,1,n,y,pos1[y],-pos2[y],-1);
        swap(pos2[x],pos2[y]);swap(pos1[x],pos1[y]);
        insert1(1,1,n,x,pos1[x],pos2[x],1);insert1(1,1,n,y,pos1[y],pos2[y],1);
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值