方队 - 启发式合并 - 主席树

(其实是启发式分裂?大雾
题目大意:n名同学要进行一次方队展示。方队展示的全过程如下:初始时,所有同学站成一横行,从左到右第i名同学编号为i,身高为ai。然后,所有同学按照一定的顺序依次出队,第i名出队的同学编号为bi。每名同学出队后,原先该同学所在的这一行会进行“变队形”操作:原先在该同学左侧的同学位置不动,在右侧的同学整体移动到队伍最后方组成新的一行,并保持他们的相对位置不变,其效果是原先的这一行分裂成了两行(注意这两行均有可能为空)。变队形前后所有同学的编号和身高不变。在同学们看来,从左往右身高依次递增的队形是最美观的。因此他们定义某一行的“不美观度”如下:设这一行有k名同学,第i名同学的身高为qi,则其“不美观度”为有序数对(i,j)的数量,满足1<=i<j<=k且qi>qj。特别地,若k=0或k=1,则这一行的“不美观度”为0。现在,你需要帮助同学们求出:每名同学出队之前,方队中“不美观度”最大的一行的“不美观度”是多少。
题解:每次分裂的时候暴力扫描小的一边更新答案,通过加入主席树区间询问若当前节点和为0则return掉、维护ans的堆的时候0不要push进去、如果当前答案是0那么之后答案也是0、求区间左右端点不要lowerbound两次而是先求一次然后it++、最后一个优化时求区间逆序对的时候如果区间比较小就采取暴力(因为常数小),这样就能足够快了。

// luogu-judger-enable-o2
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<set>
#include<utility>
#define gc getchar()
#define lint long long
#define mp make_pair
#define fir first
#define sec second
#define inf (LLONG_MIN/100)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define N 100010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,lint> pili;
typedef set<pili> spili;
typedef spili::iterator spilit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int a[N],n;spili ps;multiset<lint> ans;
struct segment{
    lint s;segment *ch[2];
}*T[N];
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->s=0;int mid=(l+r)>>1;if(l==r) return 0;
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),0;
}
int update(segment* &x,segment* &y,int p,int v,int l,int r)
{
    x=new segment,x->ch[0]=y->ch[0],x->ch[1]=y->ch[1],x->s=y->s+v;
    if(l==r) return 0;int mid=(l+r)>>1;
    if(p<=mid) update(x->ch[0],y->ch[0],p,v,l,mid);
    else update(x->ch[1],y->ch[1],p,v,mid+1,r);
    return 0;
}
lint query(segment* &rt,int s,int t,int l,int r)
{
    if((s<=l&&r<=t)||!rt->s) return rt->s;int mid=(l+r)>>1;
    lint ans=0;if(s<=mid) ans+=query(rt->ch[0],s,t,l,mid);
    if(mid<t) ans+=query(rt->ch[1],s,t,mid+1,r);return ans;
}
int b1[55],b2[55];
inline lint query(int l,int r,int s,int t) { if(l>r||s>t) return 0;return query(T[r],s,t,1,n)-query(T[l-1],s,t,1,n); }
inline lint calcA(int l,int r)
{
    if(r-l+1<=30) { int ans=0;rep(i,l,r) rep(j,i+1,r) ans+=(a[i]>a[j]);return ans; }
    lint ans=0ll;rep(i,l,r) ans+=query(i+1,r,1,a[i]-1);return ans;
}
inline lint calcB1(int l,int r,int s,int t)
{
    if(t-s+1<=50)
    {
        int ans=0;
        int c1=0;rep(i,l,r) b1[++c1]=a[i];sort(b1+1,b1+c1+1);
        int c2=0;rep(i,s,t) b2[++c2]=a[i];sort(b2+1,b2+c2+1);
        for(int i=1,j=0;i<=c1;i++,ans+=j)
            while(j<c2&&b1[i]>b2[j+1]) j++;return ans;
    }
    lint ans=0;rep(i,l,r) ans+=query(s,t,1,a[i]-1);return ans;
}
inline lint calcB2(int l,int r,int s,int t)
{
    if(r-l+1<=50)
    {
        int ans=0;
        int c1=0;rep(i,l,r) b1[++c1]=a[i];sort(b1+1,b1+c1+1);
        int c2=0;rep(i,s,t) b2[++c2]=a[i];sort(b2+1,b2+c2+1);
        for(int i=1,j=0;i<=c1;i++,ans+=j)
            while(j<c2&&b1[i]>b2[j+1]) j++;return ans;
    }
    lint ans=0;rep(i,s,t) ans+=query(l,r,a[i]+1,n);return ans;
}
char ss[N*22],tt[20];int ssl,ttl;
inline int show(lint x)
{
    if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=x%10+'0';
    for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n';
}
int main()
{
    n=inn();lint A,B,C,las;rep(i,1,n) a[i]=inn();
    build(T[0],1,n);rep(i,1,n) update(T[i],T[i-1],a[i],1,1,n);
    A=calcA(1,n),ps.insert(mp(0,A)),ps.insert(mp(n+1,0)),ans.insert(-A);
    rep(i,1,n)
    {
        multiset<lint>::iterator it=ans.lower_bound(inf);
        show(las=(it==ans.end()?0:-*it));int p=inn()^(int(las%n));
        if(las==0) { rep(j,i+1,n) show(0);break; }
        spilit pre=--ps.lower_bound(mp(p,0)),nxt=pre;nxt++;
        int L=pre->fir+1,R=nxt->fir-1,lsz=p-L+1,rsz=R-p;//[L,p],(p,R]
        if(lsz<rsz) A=calcA(L,p),B=calcB1(L,p,p+1,R),C=pre->sec-A-B;
        else C=calcA(p+1,R),B=calcB2(L,p,p+1,R),A=pre->sec-B-C;
        A-=query(L,p-1,a[p]+1,n),B-=query(p+1,R,1,a[p]-1);
        (pre->sec?ans.erase(ans.find(-pre->sec)),0:0),
        (A?ans.insert(-A),0:0),(C?ans.insert(-C),0:0),
        ps.erase(pre),ps.insert(mp(L-1,A)),ps.insert(mp(p,C));
    }
    return fwrite(ss+1,sizeof(char),ssl,stdout),0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82763304