标签:class name down 缩小 gif mod hid 多少 update
题意:给定一个排列,和 n 个地雷,按顺序将排列放入集合,遇到地雷则删去集合最大值,求地雷个数为 i 个时,集合最终的最大值为多少。
分析:首先可以看出答案一定是一个非递增序列,考虑类似二分的操作。对于每个节点 i ,若 i 点之后 >= pi 的数量小于等于后面地雷的数量,那 pi 一定会被炸掉,但这样不好维护。依据这点,我们可以尝试枚举答案 x ,每个位置记录 ( >=x的数量 - 地雷的数量) ,当所有的位置的值都 <=0 时,说明答案能取。
题解:按照分析写,区间维护和全局最大值用线段树就行,在缩小答案和增加地雷时,都是前缀的形式+1 -1,因为我们统计的是每个位置之后的数量,那么对于修改时在当前位置之后的结果是没有影响的。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3e5 + 10; ll mod=998244353; ll n,tot,m; int a[N],c[N],mp[N]; int tr[N<<2],tag[N<<2]; void push_up(int now){ tr[now]=max(tr[now<<1],tr[now<<1|1]); } void push_down(int now,int l,int r){ int mid=(l+r)/2; tag[now<<1]+=tag[now]; tr[now<<1]+=tag[now]; tag[now<<1|1]+=tag[now]; tr[now<<1|1]+=tag[now]; tag[now]=0; } void update(int now,int nl,int nr,int l,int r,int v){ if(l>=nl&&r<=nr) {tr[now]+=v;tag[now]+=v;return;} push_down(now,l,r); int mid=(l+r)/2; if(mid>=nl) update(now<<1,nl,nr,l,mid,v); if(mid+1<=nr) update(now<<1|1,nl,nr,mid,r,v); push_up(now); } int main() { // freopen("../in.in", "r", stdin); // ios::sync_with_stdio(false); ll k, _; // cin>>_; cin>>n; for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[a[i]]=i; for(int i=1;i<=n;i++) scanf("%d",&c[i]); int ans=n; update(1,1,mp[ans],1,n,1); for(int i=1;i<n;i++){ printf("%d ",ans); update(1,1,c[i],1,n,-1); while(tr[1]<=0){ ans--; update(1,1,mp[ans],1,n,1); } } printf("%d\n",ans); return 0; }
标签:class name down 缩小 gif mod hid 多少 update
原文地址:https://www.cnblogs.com/yzccccc/p/14397837.html