LUOGU P3759 [TJOI2017]不勤勞的圖書管理員(樹套樹)
阿新 • • 發佈:2019-02-25
++ long long sin 區間 iostream digi 討論 str clas
傳送門
解題思路
和以前做過的一道題有點像,就是區間逆序對之類的問題,用的是\(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; }
LUOGU P3759 [TJOI2017]不勤勞的圖書管理員(樹套樹)