[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
",id);
}else{
LL id=del_lie(x,y);
printf("%lld
",id);
G[n+1].push_back(id);
id=del_hang(x);
G[x].push_back(id);
}
}
return 0;
}/*
*/