P2839 [国家集训队] middle 题解
Richard_Whr · · 题解
为啥没人写这个思路,可能是区间修改主席树不好写吧。
首先看到中位数这种只关注相对排名的东西肯定是要二分了。
用形式化的东西刻画这个
设
区间
发现求出
这个
设
则上面的东西又可以表示成 :
移项,分离
在本题中有:
如果没有
考虑用主席树维护这个信息,第
回到
最后思考实现,考察一个位置加入主席树的时候需要哪些操作,以及查询的时候需要哪些操作。
- 在某棵树上添加某个位置的贡献:
考虑到这个位置
- 查询维护形式的
max,min :
相当于求区间
直接写个标记永久化的区间修改主席树即可,注意 tr[u].maxv=max(tr[ls].maxv,tr[rs].maxv)+tr[u].add;
附上AC代码:
#include<bits/stdc++.h>
#define ls tr[u].l
#define rs tr[u].r
using namespace std;
const int N=2e4+10,Inf=1e6;
int a[N];
struct Tree
{
int l,r;
int maxv,minv;
int add;
}tr[N*30];
int root[N],idx;
int n,m,q;
vector<int> nums;
vector<int> Pos[N];
inline void pushup(int u)
{
tr[u].maxv=max(tr[ls].maxv,tr[rs].maxv);
tr[u].minv=min(tr[ls].minv,tr[rs].minv);
}
inline int build(int l,int r)
{
int u=++idx;
if(l==r) tr[u]={0,0,l,l,0};
else
{
int mid=l+r>>1;
ls=build(l,mid),rs=build(mid+1,r);
pushup(u);
}
return u;
}
inline int modify(int p,int l,int r,int ql,int qr,int c)
{
int u=++idx;
tr[u]=tr[p];
if(l>=ql && r<=qr) tr[u].maxv+=c,tr[u].minv+=c,tr[u].add+=c;
else
{
int mid=l+r>>1;
if(ql<=mid) ls=modify(tr[p].l,l,mid,ql,qr,c);
if(qr>mid) rs=modify(tr[p].r,mid+1,r,ql,qr,c);
tr[u].maxv=max(tr[ls].maxv,tr[rs].maxv)+tr[u].add;
tr[u].minv=min(tr[ls].minv,tr[rs].minv)+tr[u].add;
}
return u;
}
inline int query_max(int u,int l,int r,int ql,int qr,int c)
{
if(!u) return -Inf;
if(l>=ql && r<=qr) return tr[u].maxv+c;
else
{
c+=tr[u].add;
int mid=l+r>>1,res=-Inf;
if(ql<=mid) res=max(res,query_max(ls,l,mid,ql,qr,c));
if(qr>mid) res=max(res,query_max(rs,mid+1,r,ql,qr,c));
return res;
}
}
inline int query_min(int u,int l,int r,int ql,int qr,int c)
{
if(!u) return Inf;
if(l>=ql && r<=qr) return tr[u].minv+c;
else
{
c+=tr[u].add;
int mid=l+r>>1,res=Inf;
if(ql<=mid) res=min(res,query_min(ls,l,mid,ql,qr,c));
if(qr>mid) res=min(res,query_min(rs,mid+1,r,ql,qr,c));
return res;
}
}
inline int solve(int a,int b,int c,int d)
{
int l=1,r=m,ans=1;
while(l<=r)
{
int mid=l+r>>1,k=mid-1;
int A=query_max(root[k],0,n,c,d,0),B=query_min(root[k],0,n,a-1,b-1,0);
if(A>=B) ans=mid,l=mid+1;
else r=mid-1;
}
return nums[ans-1];
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
tr[0].maxv=-Inf,tr[0].minv=Inf;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],nums.push_back(a[i]);
sort(nums.begin(),nums.end());
nums.erase(unique(nums.begin(),nums.end()),nums.end());
m=nums.size();
for(int i=1;i<=n;i++) a[i]=lower_bound(nums.begin(),nums.end(),a[i])-nums.begin()+1,Pos[a[i]].push_back(i);
root[0]=build(0,n);
for(int i=1;i<=m;i++)
{
root[i]=root[i-1];
for(auto x:Pos[i]) root[i]=modify(root[i],0,n,x,n,-2);
}
int ans=0;
cin>>q;
while(q--)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
a=(a+ans)%n,b=(b+ans)%n,c=(c+ans)%n,d=(d+ans)%n;
vector<int> vec;vec.push_back(a+1),vec.push_back(b+1),vec.push_back(c+1),vec.push_back(d+1);
sort(vec.begin(),vec.end());
a=vec[0],b=vec[1],c=vec[2],d=vec[3];
ans=solve(a,b,c,d);
cout<<ans<<"\n";
}
return 0;
}
跑得还挺快,只有