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;
}