CF1340F Nastya and CBS
题意:
\(n,k,q \leq 10^5\)。
题解:考虑到暴力的做法是用栈模拟括号序列匹配的过程,我们尝试使用分块,将元素个数减小至\(O(\sqrt n)\)级别。
对于每个块,我们用栈来模拟暴力匹配的过程。如果两个相邻的左右括号出现适配,那么我们称这个块是不合法的,那么所有完全包含这个区间的询问也就是不合法的。可以想象,对于一个合法的块,它匹配剩下的一定是\(x\)个右括号和\(y\)个左括号。
那么在查询时,我们就能以一堆左/右括号为单位进行匹配了。令\(pre_{i,j}\)表示第\(i\)个块的后\(j\)个右括号的绝对值的哈希值,\(suf_{i,j}\)表示第\(i\)个块的前\(j\)个左括号的哈希值,然后用栈模拟匹配就行了。
由于需要进行结构体的赋值操作,可以使用指针代替vector或普通数组做到\(O(1)\)赋值。具体实现可以看代码。
修改时就重构一下块。
时间复杂度:\(O((n+q)\sqrt n)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const int Mod=1e9+7,P=19260817,invp=494863259;
int n,m,q,a[101000],sit,X,Y;
int len,b[101000],S,ned[330],sn[330];
int p[101000],inv[101000];
int s[101000],R;vector<int>vec;
IN Pow(int x,int y=Mod-2){
re res=1;
while(y){
if(y&1)res=(ll)res*x%Mod;
x=(ll)x*x%Mod;
y>>=1;
}
return res;
}
IN Plus(int x,int y){(x+=y)>=Mod?x-=Mod:0;return x;}
struct Hash{
int *has;int len;
I init(int x){len=0;has=new int[x+1];has[0]=0;}
I insert(int x){++len;has[len]=Plus((ll)has[len-1]*P%Mod,x);}
IN calc(int x){if(x>len)return -1;return Plus(has[len],Mod-(ll)has[len-x]*p[x]%Mod);}
I delet(int x){len-=x;}
}pre[320],suf[320],tmp;
stack<Hash>st;
IN gethas(){
re res=0;
for(auto d:vec)res=Plus((ll)res*P%Mod,d);
return res;
}
I get(int x){
if(!ned[x])return;
ned[x]=0;
static int l,r;l=(x-1)*len+1;r=min(n,x*len);
R=0;sn[x]=0;
F(i,l,r){
if(a[i]>0||(a[i]<0&&(!R||s[R]<0))){s[++R]=a[i];continue;}
if((a[i]+s[R]))return sn[x]=1,void();
R--;
}
vec.clear();while(R&&s[R]>0)vec.emplace_back(s[R]),R--;reverse(vec.begin(),vec.end());
suf[x].init(vec.size());for(auto w:vec)suf[x].insert(w);
pre[x].init(R);while(R&&s[R]<0)pre[x].insert(-s[R]),R--;
}
IN ques(int x,int y){
if(!((y-x)&1))return 0;
static int l,r;l=b[x];r=b[y];
if(r-l<2){
while(R)R--;
F(i,x,y){
if(a[i]>0){s[++R]=a[i];continue;}
if(!R||(a[i]+s[R]))return 0;
R--;
}
if(!R)return 1;
return 0;
}
F(i,l+1,r-1){
get(i);
if(sn[i])return 0;
}
while(R)R--;
F(i,x,min(n,len*l)){
if(a[i]>0){s[++R]=a[i];continue;}
if(!R||(a[i]+s[R]))return 0;
R--;
}
suf[0].init(R);
vec.clear();while(R)vec.emplace_back(s[R]),R--;reverse(vec.begin(),vec.end());
for(auto w:vec)suf[0].insert(w);
while(R)R--;
F(i,(r-1)*len+1,y){
if(a[i]>0||(a[i]<0&&(!R||s[R]<0))){s[++R]=a[i];continue;}
if((a[i]+s[R]))return 0;
R--;
}
if(R&&s[R]>0)return 0;
pre[0].init(R);while(R)pre[0].insert(-s[R]),R--;
while(!st.empty())st.pop();st.emplace(suf[0]);
F(i,l+1,r){
if(i<r)tmp=pre[i];else tmp=pre[0];
while(tmp.len&&!st.empty()){
if(st.top().len>=tmp.len){
if(st.top().calc(tmp.len)^tmp.calc(tmp.len))return 0;
st.top().delet(tmp.len);
if(!st.top().len)st.pop();
tmp.len=0;
break;
}
if(st.top().calc(st.top().len)^tmp.calc(st.top().len))return 0;
tmp.delet(st.top().len);st.pop();
}
if(tmp.len)return 0;
if(i==r){
while(!st.empty()&&!st.top().len)st.pop();
if(st.empty())return 1;
return 0;
}
st.emplace(suf[i]);
}
return 0;
}
int main(){
read(n);read(m);p[0]=1;F(i,1,n)p[i]=(ll)p[i-1]*P%Mod;inv[0]=1;F(i,1,n)inv[i]=(ll)inv[i-1]*invp%Mod;
F(i,1,n)read(a[i]);
len=ceil(sqrt(n)+0.5);F(i,1,n)b[i]=((i-1)/len)+1;S=b[n];
F(i,1,S)ned[i]=1;
read(q);
while(q--){
read(sit);read(X);read(Y);
if(sit==1)a[X]=Y,ned[b[X]]=1;
else{
if(ques(X,Y))cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}
/*
10 10
10 4 2 -2 1 -1 -4 8 -8 -10
100
1 1 4
1 10 -4
2 6 9
1 3 4
1 4 -4
2 2 8
2 3 4
2 2 9
2 3 7
2 8 9
2 2 4
2 1 7
2 3 8
1 5 6
1 6 -6
2 5 6
1 8 5
1 9 -5
1 3 7
1 4 -7
1 8 10
1 9 -10
1 2 8
1 7 -8
2 3 4
2 4 6
2 1 3
1 8 1
1 9 -1
2 2 5
1 1 9
1 10 -9
1 5 4
1 6 -4
1 5 4
1 6 -4
2 2 7
2 8 9
2 2 7
2 2 7
1 2 3
1 7 -3
1 3 7
1 4 -7
2 1 10
*/