2 条题解
-
0
#include<bits/stdc++.h> using namespace std; const int N=5e4+5,B=300,M=65; int n,q,a[N],op,x,y,vs,*v,*w; int be[N],en[B],si[B],_n,ans; struct no{ int o[B+5],w[M],v[M],w2[M],v2[M],vs,vs2,all; void build(int l,int r){ for(int i=1;i<=r-l+1;++i)o[i]=0;all=vs=vs2=0; for(int i=l;i<=r;++i){ for(int j=1;j<=vs;++j)v[j]|=a[i]; v[++vs]=a[i];w[vs]=i;all|=a[i]; if(v2[vs2]<all)v2[++vs2]=all,w2[vs2]=i; int k=vs;vs=0; for(int j=1;j<=k;++j){ if(v[j]!=v[vs])v[++vs]=v[j];w[vs]=w[j]; o[i-w[j]+1]=max(o[i-w[j]+1],v[j]); } } reverse(v+1,v+vs+1);reverse(w+1,w+vs+1); for(int i=1;i<=r-l+1;++i)o[i]=max(o[i],o[i-1]); } }t[B]; int main(){ scanf("%d%d",&n,&q); for(int i=1;i<=n;++i)scanf("%d",&a[i]),be[i]=i/B+1,en[be[i]]=i; _n=be[n]; for(int i=1;i<=_n;++i)t[i].build(en[i-1]+1,en[i]),si[i]=en[i]-en[i-1]; for(;q--;){ scanf("%d%d",&op,&x); if(op==1){ scanf("%d",&y);a[x]=y;t[be[x]].build(en[be[x]-1]+1,en[be[x]]); }else{ ans=n+1; for(int i=1;i<=_n;++i)for(int j=min(ans,si[i]);j>=1;--j)if(t[i].o[j]>=x)ans=j;else break; vs=0; for(int i=1;i<=_n;++i){ for(int j=1;j<=t[i].vs2;++j){ y=t[i].v2[j]; for(;vs&&t[i].w2[j]-w[vs]+1>=ans;)--vs; if(!vs)break; if((y|v[vs])>=x){ for(;vs&&(y|v[vs])>=x;)--vs; ans=t[i].w2[j]-w[vs+1]+1; } } int V=vs,*v2=v,*w2=w;y=t[i].all; v=t[i].v;w=t[i].w;vs=t[i].vs; for(int i=1;i<=V;++i)if((y|v2[i])!=y)v[++vs]=y|=v2[i],w[vs]=w2[i]; } printf("%d\n", ans==n+1?-1:ans); } } } -
0
#include <bits/stdc++.h>//55分代码 #define int long long using namespace std; const int N = 5e4 + 10, sqrtN = 250; // 单点修改,查询区间 or 和 >= k 的最短长度 // a[i]记录每个点的值,b[i]记录每个点i所在块; // block_or[i]记录第i个块的or和,total_or记录整个序列的or和 // 每个块i的左端点L[i]、右端点R[i] int n, q, a[N], b[N], L[sqrtN], R[sqrtN], block_or[sqrtN], total_or; // 分块查询区间 [l, r] 的 or 和 int query_or(int l, int r) { int res = 0; if (b[l] == b[r]) { for (int i = l; i <= r; i++) res |= a[i]; } else { for (int i = l; i <= R[b[l]]; i++) res |= a[i]; for (int i = b[l] + 1; i <= b[r] - 1; i++) res |= block_or[i]; for (int i = L[b[r]]; i <= r; i++) res |= a[i]; } return res; } signed main() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); cin >> n >> q; for (int i = 1; i <= n; i++) { cin >> a[i]; } int B = sqrt(n), cnt = (n + B - 1) / B; for (int i = 1; i <= n; i++) { b[i] = (i - 1) / B + 1; } for (int i = 1; i <= cnt; i++) { L[i] = (i - 1) * B + 1; R[i] = min(i * B, n); } total_or = 0; for (int i = 1; i <= cnt; i++) { block_or[i] = 0; for (int j = L[i]; j <= R[i]; j++) { block_or[i] |= a[j]; } total_or |= block_or[i]; } for (int i = 1; i <= q; i++) { int op; cin >> op; if (op == 1) { int pos, x; cin >> pos >> x; int blk = b[pos]; a[pos] = x; // 修正:必须重新计算,因为 |= 无法处理某一位从 1 变成 0 的情况 block_or[blk] = 0; for (int j = L[blk]; j <= R[blk]; j++) { block_or[blk] |= a[j]; } total_or = 0; for (int j = 1; j <= cnt; j++) { total_or |= block_or[j]; } } else { int k; cin >> k; if (total_or < k) { cout << -1 << '\n'; continue; } int ans = n + 1; // 初始化为不可能达到的最大值 for (int l = 1; l <= n; l++) { // 剪枝:如果从 l 到 n 的 or 和都小于 k,那么后面的 l 区间更短,更不可能满足,直接 break if (query_or(l, n) < k) break; // 二分查找不断缩小 limit (即右端点 r) 的范围,直到找到刚好 >= k 的最小右端点 // 因为我们只关心比当前已知最优解 ans 更短的长度,所以右端点上限为 l + ans - 1 int low = l, high = min(n, l + ans - 1); int best_r = n + 1; while (low <= high) { int mid = (low + high) / 2; if (query_or(l, mid) >= k) { best_r = mid; high = mid - 1; // 满足条件,尝试缩小右端点以寻找更短的区间 } else { low = mid + 1; // 不满足条件,必须扩大右端点 } } if (best_r <= n) { ans = min(ans, best_r - l + 1); } } cout << (ans == n + 1 ? -1 : ans) << '\n'; } } return 0; }
- 1
信息
- ID
- 11343
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 12
- 已通过
- 1
- 上传者