社区讨论
超级大常数线段树代码求卡常
P8868[NOIP2022] 比赛参与者 24已保存回复 37
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 36 条
- 当前快照
- 1 份
- 快照标识符
- @mi77qiqe
- 此快照首次捕获于
- 2025/11/20 17:12 3 个月前
- 此快照最后确认于
- 2025/11/21 00:24 3 个月前
以前我使用标准的线段树维护历史和代码,然后过了这题(但是这个东西非常的sb,要定义一大堆变量然后进行复杂的计算,不好写且很容易写错)。
code 1
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;
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 条回复,欢迎继续交流。
正在加载回复...