P1975 [國家集訓隊]排隊 題解
阿新 • • 發佈:2021-08-29
問題描述
求每次序列兩個數交換過後的逆序對數
問題求解
我們能發現,假設我們交換 \(l,r\) 兩個數,,那麼顯然從 \(1\) 到 \(l-1\) 和 \(r+1\) 到 \(N\) 的數是不受影響的,那麼我們只需要討論 \(l,r\) 之間的就好了
我們先考慮刪去數,刪去 \(l,r\) 中在 \([1,a[r]-1]\) 之間的數 ,和 \([a[r]+1,MAXN]\) 之間的數,因為原來他們產生了貢獻
然後加上貢獻, \(l,r\) 中在\([1,a[r]+1]\) 和 \([a[l],MAXN]\) 之間的數
然後看 \(a[l],a[r]\) 是否產生貢獻,加上一些小細節就好了
在一個區間裡面查詢一段數值的數,樹狀陣列套權值線段樹就好了
程式碼實現
程式碼不長
#include<bits/stdc++.h> const int maxn=2e5+5; int tot,N,hsh[maxn],a[maxn],root[maxn],Ans,c[maxn],sz,M; struct node{ int sum,ls,rs; }tree[maxn*40]; struct IO{ static const int S=1<<21; char buf[S],*p1,*p2;int st[105],Top; ~IO(){clear();} inline void clear(){fwrite(buf,1,Top,stdout);Top=0;} inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;} inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='r');return *this;} template<typename T>inline IO&operator >> (T&x){ x=0;bool f=0;char ch=gc(); while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();} while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc(); f?x=-x:0;return *this; } inline IO&operator << (const char c){pc(c);return *this;} template<typename T>inline IO&operator << (T x){ if(x<0) pc('-'),x=-x; do{st[++st[0]]=x%10,x/=10;}while(x); while(st[0]) pc('0'+st[st[0]--]); return *this; } }fin,fout; inline void Bit_add(int x,int data){ for(int i=x;i<=maxn;i+=i&-i) c[i]+=data; return ; } inline int Bit_get(int x){ int ret=0; for(int i=x;i;i-=i&-i)ret+=c[i]; return ret; } void modify(int &x,int l,int r,int pos,int v){ if(!x)x=++sz;tree[x].sum+=v; if(l>=r)return ; int mid=(r-l>>1)+l; pos<=mid?modify(tree[x].ls,l,mid,pos,v):modify(tree[x].rs,mid+1,r,pos,v); return ; } int query(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr) return tree[x].sum; int mid=(r-l>>1)+l; int ret=0; (ql<=mid)&&(ret+=query(tree[x].ls,l,mid,ql,qr),0); (qr>mid)&&(ret+=query(tree[x].rs,mid+1,r,ql,qr),0); return ret; } inline void add(int x,int y,int v){ for(int i=x;i<=maxn;i+=i&-i) modify(root[i],1,tot,y,v); } inline int ask(int l,int r,int ql,int qr){ if(l>r||ql>qr) return 0; int ret=0;l--; for(int i=r;i;i-=i&-i) ret+=query(root[i],1,tot,ql,qr); for(int i=l;i;i-=i&-i) ret-=query(root[i],1,tot,ql,qr); return ret; } int main(){ freopen("P1975.in","r",stdin); freopen("P1975.out","w",stdout); fin>>N; for(int i=1;i<=N;i++)fin>>a[i],hsh[i]=a[i]; std::sort(hsh+1,hsh+1+N); tot=std::unique(hsh+1,hsh+N+1)-hsh-1; for(int i=N;i;i--){ a[i]=std::lower_bound(hsh+1,hsh+1+tot,a[i])-hsh; Ans+=Bit_get(a[i]-1); Bit_add(a[i],1); } for(int i=1;i<=N;i++) add(i,a[i],1); fin>>M;fout<<Ans<<'\n'; for(int i=1;i<=M;i++){ int l,r;fin>>l>>r; (l>r)&&(std::swap(l,r),0); Ans+=ask(l+1,r-1,1,a[r]-1); Ans-=ask(l+1,r-1,a[r]+1,tot); Ans+=ask(l+1,r-1,a[l]+1,tot); Ans-=ask(l+1,r-1,1,a[l]-1); (a[l]>a[r])&&(Ans--,0); (a[l]<a[r])&&(Ans++,0); add(l,a[l],-1),add(r,a[r],-1); add(l,a[r],1),add(r,a[l],1); std::swap(a[l],a[r]); fout<<Ans<<'\n'; } return 0; }