P14973 『GTOI - 2D』木棍

多次查询考虑价值函数能做到什么复杂度,去掉合法括号后一定形如 \(a\)) 跟着 \(b\)(,套路地放到格路上,) 看做 \(-1\)( 看做 \(+1\) 先考虑前面一段 ),则相当于从 \((0,0)\) 走到 \((x,-a)\) 其中合法的 \(x\) 是一段区间(即需要满足之后能走到 \((|S|,b-a)\)),但是在格路中 )(() 的表现是一样的(\(y\) 坐标变化抵消),但前者不合法,但是发现只有当出现 \(y<-a\) 时会出现这种情况,否则每个 ( 之后必定有 ) 消掉。而后半段是经典的,等价从 \((0,0)\) 走到 \((|S|-x,b)\) 不能碰到 \(y=-1\)。前后两段的合并形如卷积,但是发现其实限制都是不能碰到 \(y=-a-1\),则能够容斥计算一定碰到 \(y=-a\),不能碰到 \(y=-a-1\)\((0,0)\) 走到 \((|S|,b-a)\) 的方案数,都是经典的反射容斥单线情况。详见 反射容斥

而取反部分容易线段树维护出每个子串去掉合法括号后的情况。

Takanashi Rikka
#include<bits/stdc++.h>
using namespace std;
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
inline void cmx(auto &x,ll y){if(y>x)x=y;}
inline void cmn(auto &x,ll y){if(y<x)x=y;}
inline int max(vector<int>w){int res=-1e9;for(int i:w)cmx(res,i);return res;}
inline int min(vector<int>w){int res=1e9;for(int i:w)cmn(res,i);return res;}
#define pcount(x) __builtin_popcountll(x)
const int N=5e5+5,mod=998244353;
#define int ll
char s[N];int fac[N],ifac[N];
ll qp(ll x,int y=mod-2){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
struct node{int l,r,cl[2],cr[2];bool laz;}t[N<<2];
node merge(node x,node y){
	node res={x.l,y.r};
	for(int i:{0,1}){
		res.cl[i]=x.cl[i],
		res.cr[i]=y.cr[i];
		if(x.cr[i]>y.cl[i])
  			 res.cr[i]+=x.cr[i]-y.cl[i];
		else res.cl[i]+=y.cl[i]-x.cr[i];
	}
	return res;
}
void rev(int u){
	t[u].laz^=1;
	swap(t[u].cl[0],t[u].cl[1]),
	swap(t[u].cr[0],t[u].cr[1]);
}
void pd(int u){
	if(t[u].laz)
		rev(u<<1),rev(u<<1|1),t[u].laz=0;
}
void build(int u,int l,int r){
	t[u]={l,r};
	if(l==r){
		stack<char>z;
		for(int i=l;i<=r;i++)
			if(s[i]=='1'){
				if(z.size()&&z.top()=='0')z.pop();
				else z.push('1');
			}else z.push('0');
		while(z.size())
			++(z.top()=='0'?t[u].cr[0]:t[u].cl[0]),z.pop();
		for(int i=l;i<=r;i++)
			if(s[i]=='0'){
				if(z.size()&&z.top()=='0')z.pop();
				else z.push('1');
			}else z.push('0');
		while(z.size())
			++(z.top()=='0'?t[u].cr[1]:t[u].cl[1]),z.pop();
		return;
	}
	int mid=l+r>>1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	t[u]=merge(t[u<<1],t[u<<1|1]);
}
void upd(int u,int l,int r){
	if(t[u].l>=l&&t[u].r<=r)return rev(u);
	int mid=t[u].l+t[u].r>>1;pd(u);
	if(l<=mid)upd(u<<1,l,r);
	if(r>mid)upd(u<<1|1,l,r);
	t[u]=merge(t[u<<1],t[u<<1|1]);
}
node query(int u,int l,int r){
	if(t[u].l>=l&&t[u].r<=r)return t[u];
	int mid=t[u].l+t[u].r>>1;pd(u);
	if(r<=mid)return query(u<<1,l,r);
	if(l>mid)return query(u<<1|1,l,r);
	return merge(query(u<<1,l,r),query(u<<1|1,l,r));
}
int C(int x,int y){return fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
int calc(int x,int y){return C(x,(x+y)/2);}
void UesugiErii(){
	int n;cin>>n>>(s+1);
	build(1,1,n);
	for(int i=fac[0]=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
	ifac[n]=qp(fac[n],mod-2);
	for(int i=n;i;i--)ifac[i-1]=ifac[i]*i%mod;
	int q;cin>>q;
	while(q--){
		int op,l,r;cin>>op>>l>>r;
		if(op==1)upd(1,l,r);
		else{
			node res=query(1,l,r);
			int x=r-l+1,tmp=max(res.cl[0],res.cr[0]),y=res.cr[0]-res.cl[0],k=-res.cl[0];
			// cerr<<"**"<<res.cl[0]<<' '<<res.cr[0]<<'\n';
			cout<<(calc(x,2*k-y)-calc(x,2*(k-1)-y)+mod)%mod<<'\n';
			// cout<<calc(y+k,x-k)-calc(y+(k-1),x-(k-1))<<'\n';
			// cerr<<y+k<<' '<<x-k<<' '<<y+(k-1)<<' '<<x-(k-1)<<'\n';
		}
	}
}
signed main(){
	//IO();//cfast;
	int _=1;//cin>>_;
	for(;_;_--)UesugiErii();
	return 0;
}
posted @ 2026-01-19 07:41  Uesugi1  阅读(1)  评论(0)    收藏  举报