社区讨论

超级大常数线段树代码求卡常

P8868[NOIP2022] 比赛参与者 24已保存回复 37

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
36 条
当前快照
1 份
快照标识符
@mi77qiqe
此快照首次捕获于
2025/11/20 17:12
3 个月前
此快照最后确认于
2025/11/21 00:24
3 个月前
查看原帖
以前我使用标准的线段树维护历史和代码,然后过了这题(但是这个东西非常的sb,要定义一大堆变量然后进行复杂的计算,不好写且很容易写错)。
code 1CPP
#include<bits/stdc++.h>
#define mid ((le+ri)>>1)
#define ls (u<<1)
#define rs ((u<<1)|1)
#define lp ls,le,mid
#define rp rs,mid+1,ri
using namespace std;
typedef unsigned long long ll;
struct ms{
	ll sx,sy,sxy,s;
	ll len;
};
void pr_ms(ms &u){
	printf("%llu %llu %llu %llu %llu\n",u.sx,u.sy,u.sxy,u.s,u.len);
}
ms operator+(const ms &a,const ms &b){
	ms res=a;
	res.sx+=b.sx;
	res.sy+=b.sy;
	res.sxy+=b.sxy;
	res.s+=b.s;
	res.len+=b.len;
	return res;
}
struct tg{
	ll ax,ay,axy,ac,tx,ty;// first add,then set
	// s' = s + ac*len + ax*sx + ay*sy + axy*sxy
};
void pr_tg(tg &u){
	printf("%llu %llu %llu %llu %llu %llu\n",u.ax,u.ay,u.axy,u.ac,u.tx,u.ty);
}
tg operator*(const tg &a,const tg &b){// first use a then use b
	tg res=a;
	if(a.tx&&a.ty){
		res.ac+=a.tx*b.ax;
		res.ac+=a.ty*b.ay;
		res.ac+=a.tx*a.ty*b.axy;
		res.ac+=b.ac;
		if(b.tx) res.tx=b.tx;
		if(b.ty) res.ty=b.ty;
		return res;
	}
	if(a.tx){
		res.ac+=a.tx*b.ax;
		res.ay+=b.ay;
		res.ay+=a.tx*b.axy;
		res.ac+=b.ac;
		if(b.tx) res.tx=b.tx;
		if(b.ty) res.ty=b.ty;
		return res;
	}
	if(a.ty){
		res.ax+=b.ax;
		res.ac+=a.ty*b.ay;
		res.ax+=a.ty*b.axy;
		res.ac+=b.ac;
		if(b.tx) res.tx=b.tx;
		if(b.ty) res.ty=b.ty;
		return res;
	}
	res.ax+=b.ax;
	res.ay+=b.ay;
	res.axy+=b.axy;
	res.ac+=b.ac;
	if(b.tx) res.tx=b.tx;
	if(b.ty) res.ty=b.ty;
	return res;
}
void app(ms &a,tg &b){
	a.s+=b.ac*a.len+b.ax*a.sx+b.ay*a.sy+b.axy*a.sxy;
	if(b.tx&&b.ty){
		a.sx=b.tx*a.len;
		a.sy=b.ty*a.len;
		a.sxy=b.tx*b.ty*a.len;
	}
	else if(b.tx){
		a.sx=b.tx*a.len;
		a.sxy=b.tx*a.sy;
	}
	else if(b.ty){
		a.sy=b.ty*a.len;
		a.sxy=b.ty*a.sx;
	}
}
struct sgt{
	ms s[1000010];
	tg t[1000010];
	void det(){
		printf("--------------------\n");
		for(int i=1;i<=9;i++){
			printf("%d\n",i);
			pr_ms(s[i]);
			pr_tg(t[i]);
		}
	}
	void ch(int u,int le,int ri,tg &k){
		t[u]=t[u]*k;
		app(s[u],k);
	}
	void push_up(int u){
		s[u]=s[ls]+s[rs];
	}
	void push_down(int u,int le,int ri){
		ch(lp,t[u]);
		ch(rp,t[u]);
		t[u]=tg();
	}
	void build(int u,int le,int ri){
		if(le==ri){
			s[u].len=1;
			return;
		}
		build(lp);
		build(rp);
		push_up(u);
	}
	void upd(int u,int le,int ri,int x,int y,tg &k){
		if(x<=le&&ri<=y){
			ch(u,le,ri,k);
			return;
		}
		push_down(u,le,ri);
		if(x<=mid) upd(lp,x,y,k);
		if(y>mid) upd(rp,x,y,k);
		push_up(u);
	}
	ll que(int u,int le,int ri,int x,int y){
		if(x<=le&&ri<=y){
			return s[u].s;
		}
		push_down(u,le,ri);
		ll res=0;
		if(x<=mid) res+=que(lp,x,y);
		if(y>mid) res+=que(rp,x,y);
		return res;
	}
}t;
void tes(){
	t.build(1,1,5);
	
	tg t1={0,0,0,0,1,0};
	tg t2={0,0,0,0,0,1};
	tg t3={0,0,1,0,0,0};
	
	t.upd(1,1,5,2,4,t1);
	
	t.upd(1,1,5,3,5,t2);
	
	t.upd(1,1,5,1,3,t3);
	
	tg ts={0,0,0,0,2,0};
	t.upd(1,1,5,1,2,ts);
	
	ts={0,0,0,0,0,4};
	t.upd(1,1,5,2,4,ts);
	
	ts={0,0,1,0,0,0};
	t.upd(1,1,5,1,4,t3);
	
	for(int i=1;i<=5;i++){
		printf("%llu ",t.que(1,1,5,i,i));
	}
//	t.det();
//	printf("%llu ",t.que(1,1,1,1,1));
}
vector<pair<int,int> > q[250010];
int n,m,a[250010],b[250010];
int pa[250010],sa[250010],ta,pb[250010],sb[250010],tb;
ll ans[250010];
int main(){
	scanf("%d%d",&n,&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&b[i]);
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		q[y].push_back({x,i});
	}
	t.build(1,1,n);
	for(int i=1;i<=n;i++){
		// a
		while(ta&&sa[ta]<a[i]) ta--;
		int u=pa[ta]+1;
		tg opt={0,0,0,0,(ll)a[i],0};
		t.upd(1,1,n,u,i,opt);
		sa[++ta]=a[i];
		pa[ta]=i;
		// b
		while(tb&&sb[tb]<b[i]) tb--;
		int v=pb[tb]+1;
		opt={0,0,0,0,0,(ll)b[i]};
		t.upd(1,1,n,v,i,opt);
		sb[++tb]=b[i];
		pb[tb]=i;
		// cal
		opt={0,0,1,0,0,0};
		t.upd(1,1,n,1,i,opt);
		for(int j=0;j<(int)q[i].size();j++){
			int w=q[i][j].first,id=q[i][j].second;
			ans[id]=t.que(1,1,n,w,i);
		}
	}
	for(int i=1;i<=m;i++){
		printf("%llu\n",ans[i]);
	}
}
然后我今天突然知道这东西居然还能用矩阵维护。这样好写并且不容易写错,写起来舒服多了。
写完交上去发现 T 飞了。
有没有人帮忙卡个常。
code 2 (TLE 36 pts)CPP
#include<bits/stdc++.h>
#define mid ((le+ri)>>1)
#define ls (u<<1)
#define rs ((u<<1)|1)
#define lp ls,le,mid
#define rp rs,mid+1,ri
using namespace std;
typedef unsigned long long ll;
const int N=250010,M=5;
struct mt{
	int n,m;
	ll s[M][M];
};
mt operator*(const mt &a,const mt &b){
	mt res=mt();
	int n=a.n;
	int m=a.m;
	int k=b.m;
	res.n=n;
	res.m=k;
	for(int i=0;i<n;i++){
		for(int j=0;j<k;j++){
			for(int l=0;l<m;l++){
				res.s[i][j]+=a.s[i][l]*b.s[l][j];
			}
		}
	}
	return res;
}
mt a_cov(ll x){
	return {M,M,{
		{0,0,0,0,0},
		{0,1,x,0,0},
		{0,0,0,0,0},
		{0,0,0,1,0},
		{x,0,0,0,1},
	}};
}
mt b_cov(ll x){
	return {M,M,{
		{1,0,x,0,0},
		{0,0,0,0,0},
		{0,0,0,0,0},
		{0,0,0,1,0},
		{0,x,0,0,1},
	}};
}
mt c_add(){
	return {M,M,{
		{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},
	}};
}
mt operator+(const mt &a,const mt &b){
	mt res=a;
	int n=res.n;
	int m=res.m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			res.s[i][j]+=b.s[i][j];
		}
	}
	return res;
}
const mt bs={5,5,{
	{1,0,0,0,0},
	{0,1,0,0,0},
	{0,0,1,0,0},
	{0,0,0,1,0},
	{0,0,0,0,1},
}};
struct sgt{
	mt s[N<<2],t[N<<2];
	void push_up(int u){
		s[u]=s[ls]+s[rs];
	}
	void build(int u,int le,int ri){
		t[u]=bs;
		if(le==ri){
			s[u]={1,5,{0,0,0,0,1}};
			return;
		}
		build(lp);
		build(rp);
		push_up(u);
	}
	void ch(int u,mt k){
		s[u]=s[u]*k;
		t[u]=t[u]*k;
	}
	void push_down(int u){
		ch(ls,t[u]);
		ch(rs,t[u]);
		t[u]=bs;
	}
	void upd(int u,int le,int ri,int x,int y,mt k){
		if(x<=le&&ri<=y){
			ch(u,k);
			return;
		}
		push_down(u);
		if(x<=mid) upd(lp,x,y,k);
		if(y>mid) upd(rp,x,y,k);
		push_up(u);
	}
	ll que(int u,int le,int ri,int x,int y){
		if(x<=le&&ri<=y){
			return s[u].s[0][3];
		}
		ll res=0;
		push_down(u);
		if(x<=mid) res+=que(lp,x,y);
		if(y>mid) res+=que(rp,x,y);
		return res;
	}
}t;
vector<pair<int,int> > q[N];
int n,m,a[N],b[N];
int pa[N],sa[N],ta,pb[N],sb[N],tb;
ll ans[N];
int main(){
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	scanf("%d%d",&n,&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&b[i]);
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		q[y].push_back({x,i});
	}
	t.build(1,1,n);
	for(int i=1;i<=n;i++){
		while(ta&&sa[ta]<a[i]) ta--;
		int u=pa[ta]+1;
		t.upd(1,1,n,u,i,a_cov(a[i]));
		sa[++ta]=a[i];
		pa[ta]=i;
		while(tb&&sb[tb]<b[i]) tb--;
		int v=pb[tb]+1;
		t.upd(1,1,n,v,i,b_cov(b[i]));
		sb[++tb]=b[i];
		pb[tb]=i;
		t.upd(1,1,n,1,i,c_add());
		for(int j=0;j<(int)q[i].size();j++){
			int w=q[i][j].first,id=q[i][j].second;
			ans[id]=t.que(1,1,n,w,i);
		}
	}
	for(int i=1;i<=m;i++){
		printf("%llu\n",ans[i]);
	}
}

回复

37 条回复,欢迎继续交流。

正在加载回复...