LUOGU P3759 [TJOI2017]不勤劳的图书管理员(树套树)

传送门

解题思路

  和以前做过的一道题有点像,就是区间逆序对之类的问题,用的是\(BIT\)套权值线段树,交换时讨论一下计算答案。。跑的不如暴力快。。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=50005;
const int M=N*200;
const int MOD=1e9+7;
typedef long long LL;

inline int rd(){
	int x=0,f=1; char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f?x:-x;
}

int n,m,a[N],val[N],tot,rt[N];
LL ans;

struct Segment_Tree{
	int sum[M],num[M],ls[M],rs[M];
	void update_num(int &x,int l,int r,int pos,int k){
		if(!x) x=++tot; num[x]+=k; num[x]%=MOD;
		if(l==r) return; int mid=(l+r)>>1; 
		if(pos<=mid) update_num(ls[x],l,mid,pos,k);
		else update_num(rs[x],mid+1,r,pos,k);
	}
	void update_sum(int &x,int l,int r,int pos,int k){
		if(!x) x=++tot; (sum[x]+=k)%=MOD; 
		if(l==r) return; int mid=(l+r)>>1;
		if(pos<=mid) update_sum(ls[x],l,mid,pos,k);
		else update_sum(rs[x],mid+1,r,pos,k);
	}
	int query_sum(int x,int l,int r,int L,int R){
		if(!x) return 0; if(L<=l && r<=R) return sum[x];
		int mid=(l+r)>>1,ret=0;
		if(L<=mid) ret+=query_sum(ls[x],l,mid,L,R);
		if(mid<R) (ret+=query_sum(rs[x],mid+1,r,L,R))%=MOD;
		return ret;
	}
	int query_num(int x,int l,int r,int L,int R){
		if(!x) return 0; if(L<=l && r<=R) return num[x];
		int mid=(l+r)>>1,ret=0;
		if(L<=mid) ret+=query_num(ls[x],l,mid,L,R);
		if(mid<R) (ret+=query_num(rs[x],mid+1,r,L,R))%=MOD;
		return ret;
	}
}tree2;

struct BIT{
	inline void add(int x,int k){
		for(int i=x;i<=n;i+=i&-i) {
			tree2.update_num(rt[i],1,50000,a[x],k);
			tree2.update_sum(rt[i],1,50000,a[x],k*val[x]);
		}
	}
	inline int query_sum(int l,int r,int L,int R){
		if(l>r || L>R) return 0; int ret=0;
		for(int i=r;i;i-=i&-i) (ret+=tree2.query_sum(rt[i],1,50000,L,R))%=MOD;
		for(int i=l-1;i;i-=i&-i) (ret-=tree2.query_sum(rt[i],1,50000,L,R))%=MOD;
		return (ret+MOD)%MOD;
	}
	inline int query_num(int l,int r,int L,int R){
		if(l>r || L>R) return 0; int ret=0;
		for(int i=r;i;i-=i&-i) (ret+=tree2.query_num(rt[i],1,50000,L,R))%=MOD;
		for(int i=l-1;i;i-=i&-i) (ret-=tree2.query_num(rt[i],1,50000,L,R))%=MOD;
		return (ret+MOD)%MOD;
	}
}tree1;

int main(){
	n=rd(),m=rd(); int x,y,tmp,num,num1,num2;
	for(int i=1;i<=n;i++){
		a[i]=rd(),val[i]=rd(); tree1.add(i,1);
		ans+=tree1.query_sum(1,i,a[i]+1,50000);
		ans+=1ll*tree1.query_num(1,i,a[i]+1,50000)*val[i]%MOD;
		ans%=MOD;
	}	LL sum;
	while(m--){
		x=rd(),y=rd(); if(x>y) swap(x,y);
		if(x==y) {printf("%lld\n",ans); continue;}
		if(a[x]<a[y]) (ans+=val[x]+val[y])%=MOD;
		else (ans-=val[x]+val[y])%=MOD;
		tmp=tree1.query_sum(x+1,y-1,min(a[x],a[y]),max(a[x],a[y]));
		num=tree1.query_num(x+1,y-1,min(a[x],a[y]),max(a[x],a[y]));
		num1=tree1.query_num(x+1,y-1,1,min(a[x],a[y])-1);
		num2=tree1.query_num(x+1,y-1,max(a[x],a[y])+1,50000);
		if(a[x]<a[y]) ans+=tmp*2%MOD+1ll*num*(val[x]+val[y])%MOD,ans%=MOD;
		else ans-=tmp*2%MOD+1ll*num*(val[x]+val[y])%MOD,ans%=MOD;
		sum=1ll*(val[y]-val[x])*num1%MOD+1ll*(val[x]-val[y])*num2%MOD; sum%=MOD;
		(ans+=sum)%=MOD;
		tree1.add(x,-1); tree1.add(y,-1); swap(a[x],a[y]); swap(val[x],val[y]);
		tree1.add(x,1); tree1.add(y,1); ans=(ans+MOD)%MOD; printf("%lld\n",ans);
	}
	return 0;
}	
posted @ 2019-02-25 15:02  Monster_Qi  阅读(164)  评论(0编辑  收藏  举报