2018 ICPC 青島網路賽 Couleur
阿新 • • 發佈:2018-12-10
題意:
給出一個長度為n的序列,每次將某個子序列分成兩段,輸出所有段中逆序對最大的數目。
題解:
假設從x位置斷開,找到x最左邊的斷點l,和最右邊的斷點r,那麼就是把區間(l,r)分解為(l,x)和(x,r),如何維護兩段的逆序對個數呢?
啟發式分解
假設斷點跟靠近r,我們暴力求解出(x,r)的逆序對個數,在求解出(l,x)和(x,r)中兩段各有一個數的逆序對的個數,也就是有交叉的逆序對個數,再讓(l,r)中的逆序對個數減去那兩項就是(l,x)的逆序對個數。
暴力求解的方法:
將區間(x,r)中的元素建立名次樹,每加入一個元素之前看樹中大於它的個數,累加就是(x,r)的逆序對個數。
(l,x)是一顆名次樹,列舉(x,r)中的元素,看在(l,x)中大於它的個數,累加有交叉的逆序對個數。
進而求得(l,x)的逆序對個數。
假設斷點跟靠近l,方法基本和上面的一樣,不過需要一個交換樹的操作,原因請自己思考。
用的函式是pb_ds中rb_tree中的order_of_key
注意由於rb_tree中不能有重複元素,需要用結構體,然後過載大於號
#include<bits/stdc++.h> #include<hash_map> #define N 100010 #define INF 0x3f3f3f3f #define eps 1e-10 #define pi 3.141592653589793 #define LL long long #define pb push_back #define cl clear #define si size #define lb lower_bound #define ook order_of_key #define mem(x) memset(x,0,sizeof x) #define sc(x) scanf("%d",&x) #define scc(x,y) scanf("%d%d",&x,&y) #define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> using namespace __gnu_pbds; struct node{ int v,id; node(int a,int b){v=a;id=b;} bool operator >(node b) const {return v==b.v?id>b.id:v>b.v;} }; tree<node,null_type,greater<node>,rb_tree_tag,tree_order_statistics_node_update> T[N]; int a[N]; set<int>st; map<int,LL>mp; multiset<LL>A; int f[N]; int main() { int TT; sc(TT); while(TT--) { int n; sc(n); for (int i=1;i<=n;i++) sc(a[i]),f[i]=i;f[0]=0; LL ans=0; st.clear(); mp.clear(); A.clear(); st.insert(0); st.insert(n+1); for (int i=1;i<=n;i++) { ans+=T[0].order_of_key(node(a[i],i)); T[0].insert(node(a[i],i)); } mp[0]=ans; A.insert(ans); for (int i=1;i<=n;i++) { auto p=A.end(); p--; ans=*p; printf("%lld",ans); if (i<n) printf(" ");else puts(""); int x,l,r; sc(x); x^=ans; auto pos=st.upper_bound(x); r=*pos; pos--; l=*pos; LL tot=mp[l],tt=0,tmp=0; A.erase(A.lb(tot)); st.insert(x); if (r-x<x-l) { int tl=f[l],tx=f[x]; for (int i=x+1;i<r;i++) { T[tl].erase(node(a[i],i)); tmp+=T[tx].ook(node(a[i],i)); T[tx].insert(node(a[i],i)); } mp[x]=tmp; A.insert(tmp); for (int i=x+1;i<r;i++) tmp+=T[tl].ook(node(a[i],i)); tot=tot-tmp-T[tl].ook(node(a[x],x)); mp[l]=tot; A.insert(tot); T[tl].erase(node(a[x],x)); }else { swap(f[l],f[x]); int tl=f[l],tx=f[x]; for (int i=l+1;i<x;i++) { T[tx].erase(node(a[i],i)); tmp+=T[tl].ook(node(a[i],i)); T[tl].insert(node(a[i],i)); } mp[l]=tmp; A.insert(tmp); for (int i=l+1;i<x;i++) tmp+=r-x-T[tx].ook(node(a[i],i)); T[tx].erase(node(a[x],x)); tot=tot-tmp-r+x+1+T[tx].ook(node(a[x],x)); mp[x]=tot; A.insert(tot); } } } return 0; }