P4891 序列

[P4891 序列]{https://www.luogu.org/problemnew/show/P4891}

毒瘤线段树

区间维护:

\(pa:a<b的a积\)
\(pb:a>=b的b积\)
\(max\_a:最大a\)
\(min\_b:a<b中最小b\)
\(cnt:a<b的个数\)
\(lazy:标记下传\)

这里面的\(a\)是题目的\(C\)\(C\)省去,和前缀和差不多
首先看\(b\),确实单点修改没什么好讲的,找到最底层修改一下
这题难点主要在\(a_i\),影响到的区间为\(i+1,n\),线段树二分找到\(max_a<val\)的区间,将\(val\)放到能成为最大值的区间在传\(lazy\)标记,
每次操作后的答案为\(tree[root].pa*tree[root].pb\)

**My complete code: **

#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
LL n,m,q,maxn,id;
LL rt[27000000],ls[27000000],rs[27000000],d[27000000];
vector<LL> G[300010];
inline LL MAX(LL g1,LL g2){
    return g1>=g2?g1:g2;
}
LL query(LL &now,LL l,LL r,LL x){
    if(!now)
        now=++id;
    if(l==r)
        return l;
    LL mid=(l+r)>>1;
    LL shu=mid-l+1-d[ls[now]];
    if(x<=shu)
        return query(ls[now],l,mid,x);
    else 
        return query(rs[now],mid+1,r,x-shu);
}
void del(LL &now,LL l,LL r,LL x){
    if(!now)
        now=++id;
    d[now]++;
    if(l==r)
        return;
    LL mid=(l+r)>>1;
    if(x<=mid)
        del(ls[now],l,mid,x);
    else del(rs[now],mid+1,r,x);
}
inline LL del_hang(LL x){
    LL pos=query(rt[n+1],1,maxn,x);
    del(rt[n+1],1,maxn,pos);
    return pos>n?
        G[n+1][pos-n-1]:
        1ll*pos*m;
}
inline LL del_lie(LL x,LL y){
    LL pos=query(rt[x],1,maxn,y);
    del(rt[x],1,maxn,pos);
    return pos<m?
            1ll*(x-1)*m+1ll*pos:
            G[x][pos-m];
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&q);
    maxn=MAX(n,m)+q;
    for(int i=1;i<=q;++i){
        LL x,y;
        scanf("%lld%lld",&x,&y);
        if(y==m){
            LL id=del_hang(x);
            G[n+1].push_back(id);
            printf("%lld\n",id);
        }else{
            LL id=del_lie(x,y);
            printf("%lld\n",id);
            G[n+1].push_back(id);
            id=del_hang(x);
            G[x].push_back(id);
        }
    }
    return 0;
}/*
*/
posted @ 2018-12-22 20:01  y2823774827y  阅读(258)  评论(0编辑  收藏  举报