1 条题解
-
0
自动搬运
来自洛谷,原作者为

cyffff
Not yet for the story on the last page, it's not the end.搬运于
2025-08-24 23:16:28,当前版本为作者最后更新于2025-05-20 16:49:14,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
非常好数据结构,爱来自广东省集。
题意
给定一个长为 的正整数序列 。对于一个序列 :
- 初始有一常数 ;
- 你可以进行若干次操作,操作共有两种:
- 令 ;
- 选择 ,令 。
- 定义序列 的权值为要使 均变为 所需的最小操作次数。
接下来有 次询问,每次询问给出 ,求出 的权值。强制在线。
。
题解
由于 必须达到区间中的数的最高位,可以发现每个数最多只需要操作两次。只考虑区间内含有最高位 的数并统一减去 ,问题转化为求解 。
将上式写作 ,逆用 Hall 定理,将问题转化为二分图匹配问题,左部点 向右部点 连边,上式即为左部点失配点数。
由于所有左部点均向右部一个前缀连边,故可以以任意顺序贪心匹配,不妨按照 的顺序进行匹配。
按右端点进行扫描线,扫到 时,由于我们从右至左贪心匹配,故一定匹配 。使用 Hall 定理维护并判断是否可成功加入 ,只需要判断是否满足 即可。若不能直接匹配,则需要我们找到最左侧的匹配点 使得删去 后存在完美匹配。这只需要找到最小的 使得 ,那么 即为最小的满足 的位置。
上述操作均可使用线段树简单维护,而询问只需使用主席树维护矩形加单点求值。
精细实现可做到时间复杂度 。
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=2e5+10,K=60+2,INF=1e9; int n,k,q,t,lg[N],pw[65],rx[N],sp[N][K],cp[K],ct[K],pol[N],nx[N],rt[N][K]; ll a[N],b[N],las,st[19][N]; inline ll querymx(int l,int r){ int t=__lg(r-l+1); return max(st[t][l],st[t][r-(1<<t)+1]); } struct Segment_Trees{ #define ls (a[rt].lson) #define rs (a[rt].rson) struct node{ int lson,rson,cnt; }a[N*20]; int cnt; inline int copy(int x){ int rt=++cnt; a[rt]=a[x]; return rt; } inline void insert(int &rt,int l,int r,int p){ rt=copy(rt),a[rt].cnt++; if(l==r) return ; int mid=l+r>>1; if(p<=mid) insert(ls,l,mid,p); else insert(rs,mid+1,r,p); } inline int query(int rt,int l,int r,int L,int R){ if(!rt) return 0; if(L<=l&&r<=R) return a[rt].cnt; int mid=l+r>>1,ans=0; if(L<=mid) ans+=query(ls,l,mid,L,R); if(R>mid) ans+=query(rs,mid+1,r,L,R); return ans; } }Ts; struct Segment_Tree{ #define ls (rt<<1) #define rs (rt<<1|1) int mn[N<<2],mnp[N<<2],tag[N<<2]; inline void pushup(int rt){ mn[rt]=min(mn[ls],mn[rs])+tag[rt]; mnp[rt]=min(mnp[ls],mnp[rs]); } inline void pushtag(int rt,int v){ tag[rt]+=v,mn[rt]+=v; } inline void build(int rt,int l,int r){ if(l==r){ mn[rt]=rx[l],mnp[rt]=INF;return ; } int mid=l+r>>1; build(ls,l,mid),build(rs,mid+1,r); pushup(rt); } inline void modify(int rt,int l,int r,int p,int v){ if(l==r){ mnp[rt]=v;return ; } int mid=l+r>>1; if(p<=mid) modify(ls,l,mid,p,v); else modify(rs,mid+1,r,p,v); pushup(rt); } inline void add(int rt,int l,int r,int L,int R,int v){ if(L<=l&&r<=R) return pushtag(rt,v); int mid=l+r>>1; if(L<=mid) add(ls,l,mid,L,R,v); if(R>mid) add(rs,mid+1,r,L,R,v); pushup(rt); } inline int query1(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R) return mn[rt]; int mid=l+r>>1,ans=INF; if(L<=mid) ans=min(ans,query1(ls,l,mid,L,R)); if(R>mid) ans=min(ans,query1(rs,mid+1,r,L,R)); return ans+tag[rt]; } inline int query2(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R) return mnp[rt]; int mid=l+r>>1,ans=INF; if(L<=mid) ans=min(ans,query2(ls,l,mid,L,R)); if(R>mid) ans=min(ans,query2(rs,mid+1,r,L,R)); return ans; } inline int find(int rt,int l,int r,int L,int R,int tg=0){ if(l>R||r<L||mn[rt]+tg>=0) return -1; if(l==r) return l; tg+=tag[rt]; int mid=l+r>>1,tp=find(ls,l,mid,L,R,tg); if(tp==-1) tp=find(rs,mid+1,r,L,R,tg); return tp; } }T; vector<ll>vec; ll ask(int l,int r){ int t=__lg(querymx(l,r)); return (1ll<<t)+(r-l+1)+(sp[r][t]-sp[l-1][t])-Ts.query(rt[r][t],1,n,l,r); } void init(int n,const vector<ll>&A){ ::n=n; for(int i=1;i<=n;i++){ a[i]=A[i-1],vec.push_back(a[i]); lg[i]=__lg(a[i]),k=max(k,lg[i]); b[i]=a[i]-(1ll<<lg[i]); } for(int i=1;i<=n;i++) st[0][i]=a[i]; for(int i=1;i<=18;i++) for(int j=1;j+(1<<i)-1<=n;j++) st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]); for(int i=1;i<=n;i++){ for(int j=0;j<=k;j++) sp[i][j]=sp[i-1][j]; sp[i][lg[i]]++; } for(int j=0;j<=k;j++) ct[j]=sp[n][j],cp[j]+=ct[j],cp[j+1]+=cp[j]; for(int i=1;i<=n;i++) if(b[i]>=ct[lg[i]]) b[i]=-1; else b[i]=(lg[i]?cp[lg[i]-1]+1:1)+b[i]; for(int i=0,p=0;i<=k;i++) for(int j=0;j<ct[i];j++) rx[++p]=j; T.build(1,1,n); for(int i=1;i<=n;i++) pol[i]=n+1; for(int i=n;i;i--) if(b[i]!=-1) nx[i]=pol[b[i]],pol[b[i]]=i; for(int i=1;i<=n;i++) pol[i]=0; for(int i=1;i<=n;i++){ for(int j=0;j<=k;j++) rt[i][j]=rt[i-1][j]; if(b[i]==-1) continue; int L=lg[i]?cp[lg[i]-1]+1:1,R=cp[lg[i]]; T.add(1,1,n,b[i],R,-1); if(!pol[b[i]]) T.modify(1,1,n,b[i],i),pol[b[i]]=i; int mnp=T.find(1,1,n,L,R); if(mnp==-1) continue; int lp=T.query2(1,1,n,L,mnp); T.add(1,1,n,b[lp],R,1); int nxp=nx[pol[b[lp]]]; if(nxp>i) pol[b[lp]]=0,T.modify(1,1,n,b[lp],INF); else pol[b[lp]]=nxp,T.modify(1,1,n,b[lp],nxp); Ts.insert(rt[i][lg[i]],1,n,lp); } }
- 1
信息
- ID
- 12327
- 时间
- 6000ms
- 内存
- 512MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者