1. 程式人生 > >2018 ICPC 青島網路賽 Couleur

2018 ICPC 青島網路賽 Couleur

題意:

給出一個長度為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;
}