W
e
l
c
o
m
e
: )

P5065 [Ynoi2014] 不归之人与望眼欲穿的人们

题传

被卡常了,大败而归。

注意到是不同寻常的 or 和,不难推出最多经过 \(\log a\) 次变化就顶到值域上限。

单点修改,全局查询,所以要有一个平衡复杂度的东西,因此分块。

块内维护维护 \(f(len)\) 表示长度为 \(len\) 的所有子区间 or 和的最大值并取前缀 max,这样询问就可以直接二分找块内满足条件的最小长度了,设 \(dp_{i, j}\) 为满足 \([dp_{i, j}, i]\) or 和 \(i\) 为 1 的最大的 \(dp_{i, j}\),不难得所有 \([dp_{i, j}, i\) 才是 \(f(len)\) 的有效贡献区间,因此修改时暴力重构整个块和 \(f, dp\),每次做 ST 表即可做到修改 \(O(\sqrt{n}(\log + \log a))\)

对于跨过块的答案,考虑每个块维护前/后缀 \(\log n\) 次变化的位置,加入新的块的时候,双指针在原后缀和加入块的前缀统计贡献即可。

复杂度 \(O(m\sqrt{n}\log a)\)

Code:

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cctype>
#include <vector>
#include <queue>
#include <bitset>
#include <cmath>
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define st first
#define nd second
using namespace std;
typedef long long ll;
typedef pair <int, int> Pii;
const int INF=2147483647;
const int cp=1e9+7;
inline int plust(int x, int y){x+=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int minut(int x, int y){x-=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int read(){
	char ch=getchar();int x=0, f=1;
	while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'), x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline int ksm(int a, int b=cp-2){
	int ret=1;
	for(; b; b>>=1, a=1ll*a*a%cp)
		if(b&1) ret=1ll*ret*a%cp;
	return ret;
}
const int N=5e4+5;
const int M=1e4+4;
int n, m, B, a[N], bid[N], mxn[M], ors[M], L[M], R[M];
vector <Pii> pre[M], suf[M], pret, suft;
int dp[N][35], ST[N][35], lg[N];
vi mx[M];
int query(int l, int r){int k=lg[r-l+1];return ST[l][k]|ST[r-(1<<k)+1][k];}
void buildst(int l, int r){
	for(int i=l; i<=r; ++i) ST[i][0]=a[i];
	for(int j=1; j<=lg[r-l+1]; ++j)
		for(int i=l; i+(1<<j)-1<=r; ++i)
			ST[i][j]=ST[i][j-1]|ST[i+(1<<j-1)][j-1];
}
void rebuild(int idx, int flg){
	//整体重构,flg>0 表示 flg 被修改
	int l=L[idx], r=R[idx];
	// printf("rebuild block %d [%d %d]:%d\n", idx, l, r, flg);
	vector <Pii> ().swap(pre[idx]);
	vector <Pii> ().swap(suf[idx]);mxn[idx]=ors[idx]=0;
    for(int i=r, sf=0, lst=-1; i>=l; mxn[idx]=max(mxn[idx], a[i]), --i, lst=sf)
        if((sf|=a[i])^lst) suf[idx].pb(mp(sf, r-i+1));
    buildst(l, r);
    for(int i=l, pr=0, lst=-1; i<=r; ++i, lst=pr){
    	mx[idx][i-l+1]=0, ors[idx]|=a[i];
        if((pr|=a[i])^lst) pre[idx].pb(mp(pr, i-l+1));
        if(pr==INF) break;
    	for(int j=0; j<=30&&(1ll<<j)<=mxn[idx]; ++j){
    		if((a[i]>>j)&1) dp[i][j]=i;
    		else dp[i][j]=dp[i-1][j];
    		if(dp[i][j]>=l) 
    			mx[idx][i-dp[i][j]+1]=max(mx[idx][i-dp[i][j]+1], query(dp[i][j], i));
    	}
    }
	for(int i=1; i<=r-l+1; ++i) mx[idx][i]=max(mx[idx][i-1], mx[idx][i]);
}
int Ef(int idx, int val){
	int r=R[idx]-L[idx]+1;if(mx[idx][r]<val) return n+1;
	int l=1, ans=r;
	while(l<=r){
		int mid=l+r>>1;
		if(mx[idx][mid]>=val) ans=mid, r=mid-1;
		else l=mid+1; 
	}
	return ans;
}
signed main(){
	n=read(), m=read();lg[0]=-1;
	for(int i=1; i<=n; ++i) a[0]|=(a[i]=read()), lg[i]=lg[i>>1]+1;
	for(int i=0; i<=30; ++i) if(a[0]&(1<<i)) B=i;
	B=sqrt(n*50);//printf("block len = %d\n", B);
	for(int i=1, c=1; i<=n; i+=B){
		for(int j=0; j<B&&i+j<=n; ++j) bid[i+j]=c;
		L[c]=i, R[c]=min(i+B-1, n);
		mx[c].resize(R[c]-L[c]+2, 0);
		rebuild(c, 0);++c;
	}
	for(int i=1; i<=m; ++i){
		int op=read();
		if(op&1){
			int x=read(), y=read();a[x]=y;
			rebuild(bid[x], x);
		}
		else{
			int k=read(), sor=0, len=0;int res=n+1;
			for(int j=bid[1]; j<=bid[n]; ++j){
				if(res==n) break;
				res=min(res, Ef(j, k));
				// printf("for block %d: find [%d %d]\n", j, v.st, v.nd);
				if(j==bid[1]) 
					pret=pre[j], suft=suf[j], sor=ors[j], len=R[j]-L[j]+1;
				else{
					int sz1=suft.size(), sz2=pre[j].size();
					for(int l=sz1-1, r=0; l>=0; --l){
						while(r<sz2&&(suft[l].st|pre[j][r].st)<k) ++r;
						if(r>=sz2) break;res=min(res, suft[l].nd+pre[j][r].nd);
					}
					/*合并*/
					int lst=-1;
					vector <Pii> tmp=pre[j];
					for(auto &v:tmp) v.st|=sor, v.nd+=len;
					lst=pret.back().st;
					for(auto &v:tmp) if(v.st!=lst) pret.pb(v), lst=v.st;
					tmp=suf[j];swap(suft, tmp);
					for(auto &v:tmp) v.st|=ors[j], v.nd+=R[j]-L[j]+1;
					lst=suft.back().st;
					for(auto &v:tmp) if(v.st!=lst) suft.pb(v), lst=v.st;
					len+=R[j]-L[j]+1, sor|=ors[j]; 
				}
			}
			if(res<=n) printf("%d\n", res);
			else puts("-1");
		}
	}
	return 0;
}
posted @ 2023-02-08 18:47  127_127_127  阅读(28)  评论(0编辑  收藏  举报