ZOJ - 4053 Couleur(ACM-ICPC 2018 青岛赛区网络预赛 G)(主席树+线段树+启发式暴力)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/82749989

Couleur


Time Limit: 6 Seconds      Memory Limit: 131072 KB


DreamGrid has an array of  integers. On this array he can perform the following operation: choose an element that was not previously chosen and mark it as unavailable. DreamGrid would like to perform exactly operations until all the elements are marked.

DreamGrid defines the cost of a subarray as the number of inversions in the subarray. Before performing an operation, DreamGrid would like to know the maximum cost of a subarray that doesn't contain any unavailable elements.

Recall that a subarray  is a contiguous subpart of the original array where . An inversion in a subarray  is a pair of indices   such that the inequality  holds.

Input

There are multiple test cases. The first line of input contains an integer , indicating the number of test cases. For each test case:

The first line contains a single integer   -- the length of the array.

The second line contains the  values of the array  .

The third line contains a permutation , representing the indices of the elements chosen for the operations in order.

Note that the permutation is encrypted and you can get the real permutation using the following method: Let  be the answer before the -th operation. The actual index of the -th operation is  where  is bitwise exclusive or operator.

It is guaranteed that the sum of all  does not exceed .

Output

For each test case, output  integers  in a single line seperated by one space, where  is the answer before the -th operation.

Please, DO NOT output extra spaces at the end of each line, or your answer may be considered incorrect!

Sample Input

3
5
4 3 1 1 1
5 4 5 3 1
10
9 7 1 4 7 8 5 7 4 8
21 8 15 5 9 2 4 5 10 6
15
4 8 8 1 12 1 10 14 7 14 2 9 13 10 3
37 19 23 15 7 2 10 15 2 13 4 5 8 7 10

Sample Output

7 0 0 0 0
20 11 7 2 0 0 0 0 0 0
42 31 21 14 14 4 1 1 1 0 0 0 0 0 0

Hint

The decoded permutation of each test case is ,  and 


Author: LIN, Xi
Source: The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online

Submit    Status

题意:一刀刀切,求所有子串中,最大的逆序数。切N次。

解题思路:主要思想是启发式暴力。首先我们用主席树求出1~N的逆序数。这里虽然用树状数组和线段树都可以,但是我们为了可以求任意区间的逆序数所以我们用主席树,维护的是数字出现的个数。这样我们就可以在N*log(N)时间内,求出任意区间的逆序数。对于这道题而言,我们切一刀后,对于新出现的两段,如果我们都暴力的用NlogN时间算这两段的逆序数,因为会切N刀,假设每次切的都是边缘地方,那么就要暴力N*N次,那么总的时间复杂度是N*N*logN。这样是不可取的。因此考虑一种启发式算法,我们每次暴力,只暴力小的那一半,大的那一半可以通过小的那一半算出,那么我们最多暴力算N*logN次而已,那么这样子实现复杂度就变成了N*logN*logN,可以接受了!

懂得这种思想后,因为可以暴力,那么怎么做都可以了!假设我们知道一个区间,如

5 4 3 2 1

他的逆序数是10,现在切一刀变成   5  4  和  3 2 1

我们暴力算出 5 4 的逆序数为1

在暴力算的时候我们可以用 10 减 321中比5小的数的个数  减  321比4小的数的个数  减 54的逆序数,得出3 2 1 这个区间的逆序数为3。所以我们要用主席树去求逆序数而不是线段树或树状数组,这位这样才能很方便的计算出逆序数。当然求54的逆序数的时候也可用树状数组去求,这样子常数会低一点点。

那么现在暴力算法有了。那么对于每一刀,我们怎么求出这一刀所代表的区间呢?这里有很多方法,我用的是线段树区间染色思想,线段树记录的是当前位置所在区间是多少。那么对于每一刀我们就可以直接查询出区间然后开始暴力了。

那么怎么维护答案呢?可以用优先队列也可以用set,但是因为区间切一刀后会改变,所以用set好,可以删除。

#include <iostream>
#include <string.h>
#include <math.h>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int MAXN = 100050;
const int INF = 0x3f3f3f3f;

inline void scan_d(int &ret)
{
    char c;
    ret = 0;
    while ((c = getchar()) < '0' || c > '9');
    while (c >= '0' && c <= '9')
    {
        ret = ret * 10 + (c - '0'), c = getchar();
    }
}

ll sum[MAXN*30];
int A[MAXN];
int rs[MAXN*30];
int ls[MAXN*30];
int T[MAXN];
int tot=0;

void update(int P,int C,int l,int r,int &rt,int lrt){
    rt=++tot;
    ls[rt]=ls[lrt];
    rs[rt]=rs[lrt];
    sum[rt]=sum[lrt];
    if(l==r){
        sum[rt]+=C;
        return;
    }
    int m=(l+r)/2;
    if(P<=m)
        update(P,C,l,m,ls[rt],ls[lrt]);
    else
        update(P,C,m+1,r,rs[rt],rs[lrt]);
    
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}

int query(int L,int R,int l,int r,int rt,int lrt){
    if(R<L)
        return 0;
    if(L<=l&&r<=R)
        return sum[lrt]-sum[rt];
    int m=(l+r)/2;
    int ans=0;
    if(L<=m)
        ans+=query(L,R,l,m,ls[rt],ls[lrt]);
    if(R>m)
        ans+=query(L,R,m+1,r,rs[rt],rs[lrt]);
    return ans;
}

struct mynode{
    int L,R;
    ll W;
    friend bool operator <(const mynode& a,const mynode& b) {
        if(a.W==b.W){
            if(a.L==b.L)
                return a.R>b.R;
            return a.L>b.L;
        }
        return a.W>b.W;
    }
    mynode(){
        L=0,R=0,W=0;
    }
};

mynode tree[MAXN<<2];
mynode lazy[MAXN<<2];
void pushdown(int rt){
    if(lazy[rt].L!=-1){
        tree[rt<<1]=tree[rt<<1|1]=lazy[rt];
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        lazy[rt].L=-1;
    }
}
void update(int L,int R,mynode C,int l,int r,int rt){
    if(R<L)
        return;
    if(L<=l&&r<=R){
        tree[rt]=C;
        lazy[rt]=C;
        return;
    }
    pushdown(rt);
    ll m=(l+r)/2;
    if(L<=m)
        update(L,R,C,l,m,rt<<1);
    if(R>m)
        update(L,R,C,m+1,r,rt<<1|1);
}

mynode query(int C,int l,int r,int rt){
    if(l==r)
        return tree[rt];
    pushdown(rt);
    int m=(l+r)/2;
    if(C<=m)
        return query(C,l,m,rt<<1);
    else
        return query(C,m+1,r,rt<<1|1);
}


set<mynode> s;//维护答案
mynode temp;

int main()
{
    int TT;
    scan_d(TT);
    while(TT--){
        s.clear();
        tot=0;
        
        int N;
        scan_d(N);
        temp.L=1;
        temp.R=N;
        temp.W=0;
        
        for(ll i=1;i<=N;i++){
            scan_d(A[i]);
            temp.W+=query(A[i]+1,N,1,N,T[0],T[i-1]);//计算初始区间的逆序数
            update(A[i],1,1,N,T[i],T[i-1]);
        }
        
        s.insert(temp);
        update(temp.L,temp.R,temp,1,N,1);//区间染色
        
        int op;
        ll ans=0;
        for(ll q=0;q<N;q++){
            scan_d(op);
            if(q!=N-1)
                printf("%lld ",s.begin()->W);
            
            if(q==N-1){
                printf("%lld\n",s.begin()->W);
                break;
            }
            ans=s.begin()->W;
            if(ans==0){
                continue;//后面肯定都是0了
            }
            op=op^ans;
            
            mynode nn=query(op,1,N,1);//查询切一刀的那个区间  
            s.erase(nn);//删掉,因为答案会改变
            
            int L=op-nn.L;
            int R=nn.R-op;
            //启发式暴力
            if(L>R){
                mynode RN,LN;//新建两个区间
                RN.L=op+1;
                RN.R=nn.R;
                LN.L=nn.L;
                LN.R=op-1;
                LN.W=nn.W;
                
                for(ll i=RN.L;i<=RN.R;i++){
                    RN.W+=query(A[i]+1,N,1,N,T[RN.L-1],T[i-1]);
                    LN.W-=query(A[i]+1,N,1,N,T[LN.L-1],T[LN.R]);
                }
                LN.W-=RN.W;
                LN.W-=query(A[op]+1,N,1,N,T[LN.L-1],T[LN.R]);//那一刀的影响也要单独算
                LN.W-=query(1,A[op]-1,1,N,T[RN.L-1],T[RN.R]);
                
                if(LN.R>=LN.L){
                    s.insert(LN);//维护答案
                    update(LN.L,LN.R,LN,1,N,1);//区间染色
                }
                if(RN.R>=RN.L){
                    s.insert(RN);
                    update(RN.L,RN.R,RN,1,N,1);
                }
                
                
            }
            else{
                mynode RN,LN;
                RN.L=op+1;
                RN.R=nn.R;
                LN.L=nn.L;
                LN.R=op-1;
                
                RN.W=nn.W;
                for(ll i=LN.L;i<=LN.R;i++){
                    LN.W+=query(A[i]+1,N,1,N,T[LN.L-1],T[i-1]);
                    RN.W-=query(1,A[i]-1,1,N,T[RN.L-1],T[RN.R]);
                }
                RN.W-=query(1,A[op]-1,1,N,T[RN.L-1],T[RN.R]);
                RN.W-=query(A[op]+1,N,1,N,T[LN.L-1],T[LN.R]);
                RN.W-=LN.W;
                
                
                if(LN.R>=LN.L){
                    s.insert(LN);
                    update(LN.L,LN.R,LN,1,N,1);
                }
                
                if(RN.R>=RN.L){
                    s.insert(RN);
                    update(RN.L,RN.R,RN,1,N,1);
                }
                
            }
            
        }
        
        
        
    }
    
    
    return 0;
}



猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/82749989