NIT GREAT NITYACKE DESTROYS THE UNIVERSE

线段树

一般线段树维护的东西是什么?设其维护的信息的半群 \((A,+)\),维护标记的半群 \((T,\times)\) 和一种运算 \(*\mapsto A*T\to A\)

要求 \((b+c)*a=b*a+c*a\)

一般而言,矩阵是满足这东西的较为一般的东西。

注意:这里不包括 Segment Tree Beats 等基于势能分析的非传统线段树。

现在我们看题:[NOIP2022] 比赛。

扫描线,然后单调栈转化成支持 \(a·b\) 历史和、\(a,b\) 区间覆盖的数据结构。

想在 \(O(1)\) 秒钟构造出标记感觉不大现实,考虑用矩阵乘法维护标记,记 \(a,b,S,len\) 为区间 \(a/b\) 和,历史版本和,区间长度,则区间 \(a\) 加上 \(v\) 就是

\[\begin{bmatrix}a+vlen&b&ab+bv&S&len\end{bmatrix}=\begin{bmatrix}a&b&ab&S&len\end{bmatrix}\times \begin{bmatrix} 1&0&0&0&0\\0&1&v&0&0\\0&0&1&0&0\\0&0&0&1&0\\v&0&0&0&1\\\end{bmatrix} \]

区间 \(b\) 加就是:

\[\begin{bmatrix}a&b+vlen&ab+av&S&len\end{bmatrix}=\begin{bmatrix}a&b&ab&S&len\end{bmatrix}\times \begin{bmatrix} 1&0&v&0&0\\0&1&0&0&0\\0&0&1&0&0\\0&0&0&1&0\\0&v&0&0&1\\\end{bmatrix} \]

叠加上版本和就是:

\[\begin{bmatrix}a&b&ab&S+ab&len\end{bmatrix}=\begin{bmatrix}a&b&ab&S&len\end{bmatrix}\times \begin{bmatrix} 1&0&0&0&0\\0&1&0&0&0\\0&0&1&1&0\\0&0&0&1&0\\0&0&0&0&1\\\end{bmatrix} \]

然后线段树维护矩阵即可,时间复杂度 \(O((n+m)k^3\log n),k=5\),由于常数过大,可以获得 \(20pts\) 的高分。

然后我们发现,矩阵有很多地方用不上,可以直接拆开。

贡献是形如 \(len\to a,b\to ab\to S\) 的 DAG,最多有 \(9\) 个状态,然后我们只维护这 \(9\) 个数即可。

然后发现这些位置分别是 \((4,0),(4,1),(4,2),(4,3),(0,2),(0,3),(1,2),(1,3),(2,3)\)

还有两对位置的值重复。

然后把这一部分重新标号,拿出来手动维护就行了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2.5e5+5;
#define ull unsigned long long
struct qsy{
	ull a[8];
	qsy(){
		memset(a,0,sizeof(a));
	}
	qsy(int A,int B,int C,int D,int E,int F,int G){
		a[1]=A,a[2]=B,a[3]=C,a[4]=D,a[5]=E,a[6]=F,a[7]=G;
	}
};
int T,n,m;
qsy xds[maxn<<2],add[maxn<<2];
void print(qsy a,int tp){
	int mp[8][8];memset(mp,0,sizeof(mp));
	if(tp==0){
		mp[1][3]=mp[5][2]=a.a[1];
		mp[1][4]=a.a[2];
		mp[2][3]=mp[5][1]=a.a[3];
		mp[2][4]=a.a[4];
		mp[5][3]=a.a[5];
		mp[3][4]=a.a[6];
		mp[5][4]=a.a[7];
		for(int i=1;i<=5;i++)mp[i][i]=1;
		cout<<endl;
		for(int i=1;i<=5;i++){
			for(int j=1;j<=5;j++){
				cout<<mp[i][j]<<" ,";
			}
			cout<<endl;
		}
		cout<<endl;
	}else{
		cout<<"[ "<<a.a[1]<<" ,"<<a.a[2]<<" ,"<<a.a[3]<<" ,"<<a.a[4]<<" ,"<<a.a[5]<<" ]"<<endl;
	}
}
inline qsy operator *(qsy a,qsy b){
	qsy c;
	c.a[1]=a.a[1]+b.a[1];
	c.a[2]=a.a[2]+b.a[2]+a.a[1]*b.a[6];
	c.a[3]=a.a[3]+b.a[3];
	c.a[4]=a.a[4]+b.a[4]+a.a[3]*b.a[6];
	c.a[5]=a.a[3]*b.a[1]+a.a[1]*b.a[3]+a.a[5]+b.a[5];
	c.a[6]=a.a[6]+b.a[6];
	c.a[7]=a.a[7]+b.a[7]+a.a[3]*b.a[2]+a.a[1]*b.a[4]+a.a[5]*b.a[6];
//	print(a,0);cout<<"*"<<endl;print(b,0);cout<<"="<<endl;print(c,0);
	return c;
}
inline qsy operator ^(qsy a,qsy b){
	qsy c;
	c.a[1]=a.a[1]+b.a[3]*a.a[5];
	c.a[2]=a.a[2]+b.a[1]*a.a[5];
	c.a[3]=a.a[3]+b.a[1]*a.a[1]+b.a[3]*a.a[2]+b.a[5]*a.a[5];
	c.a[4]=a.a[4]+b.a[2]*a.a[1]+b.a[4]*a.a[2]+b.a[6]*a.a[3]+b.a[7]*a.a[5];
	c.a[5]=a.a[5];
//	print(a,1);cout<<"*"<<endl;print(b,0);cout<<"="<<endl;print(c,1);
	return c;
}
inline qsy operator +(qsy a,qsy b){
	for(int i=1;i<=5;i++)a.a[i]+=b.a[i];
	return a;
}
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
inline void pushup(int k){
	xds[k]=xds[ls]+xds[rs];
}
inline void ADD(int k,qsy a){
	xds[k]=(xds[k]^a);
	add[k]=add[k]*a;
}
inline bool emp(qsy a){
	for(int i=1;i<=7;i++)if(a.a[i]!=0)return 0;
	return 1;
}
inline void pushdown(int k){
	if(emp(add[k]))return ;
	ADD(ls,add[k]);ADD(rs,add[k]);
	memset(add[k].a,0,sizeof(add[k].a));
}
inline qsy maker(int tp,int v){
	qsy rt;
	if(tp==1)rt.a[3]=v;
	if(tp==2)rt.a[1]=v;
	if(tp==3)rt.a[6]=1;
	return rt;
}
void modify(int k,int l,int r,int x,int y,int tp,int v=0){
	if(x<=l&&r<=y){
		return ADD(k,maker(tp,v));
	}
	pushdown(k);
	if(x<=mid)modify(ls,l,mid,x,y,tp,v);
	if(mid<y)modify(rs,mid+1,r,x,y,tp,v);
	pushup(k);
}
ull query(int k,int l,int r,int x,int y){
	if(x<=l&&r<=y)return xds[k].a[4];
	pushdown(k);ull res=0;
	if(x<=mid)res+=query(ls,l,mid,x,y);
	if(mid<y)res+=query(rs,mid+1,r,x,y);
	return res;
}
ull ans[maxn];
vector<pair<int,int> > e[maxn];
int tpa=0,tpb=0,a[maxn],b[maxn];
pair<int,int> sta[maxn],stb[maxn];
void build(int k,int l,int r){
	xds[k].a[5]=r-l+1;
	if(l==r)return ;
	build(ls,l,mid);build(rs,mid+1,r);
}
signed main(){
// 	freopen("match3.in","r",stdin);
// 	freopen("match3.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>T>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)cin>>b[i];
	cin>>m;
	for(int i=1;i<=m;i++){
		int l,r;cin>>l>>r;
		e[r].push_back({l,i});
	}
	build(1,1,n);
	for(int i=1;i<=n;i++){
		modify(1,1,n,i,i,1,a[i]);
//		cout<<"a("<<i<<" "<<i<<")+= "<<a[i]<<endl;
		while(tpa&&a[i]>a[sta[tpa].second]){
//			cout<<"a("<<sta[tpa].first<<" "<<sta[tpa].second<<")+= "<<a[i]-a[sta[tpa].second]<<endl;
			modify(1,1,n,sta[tpa].first,sta[tpa].second,1,a[i]-a[sta[tpa].second]),--tpa;
		}
		tpa++,sta[tpa]={sta[tpa-1].second+1,i};
		modify(1,1,n,i,i,2,b[i]);
//		cout<<"b("<<i<<" "<<i<<")+= "<<b[i]<<endl;
		while(tpb&&b[i]>b[stb[tpb].second]){
//			cout<<"b("<<stb[tpb].first<<" "<<stb[tpb].second<<")+= "<<b[i]-b[stb[tpb].second]<<endl;
			modify(1,1,n,stb[tpb].first,stb[tpb].second,2,b[i]-b[stb[tpb].second]),--tpb;
		}
		tpb++,stb[tpb]={stb[tpb-1].second+1,i};
		modify(1,1,n,1,n,3);
//		cout<<"Genshin"<<endl;
		for(auto P:e[i]){
			ans[P.second]=query(1,1,n,P.first,i);
		}
	}
	for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
	return 0;
}

联考题

image

代码待补

posted @ 2023-11-02 15:24  British_Union  阅读(22)  评论(2编辑  收藏  举报