专栏文章
P10822
P10822题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio2yd8l
- 此快照首次捕获于
- 2025/12/02 12:30 3 个月前
- 此快照最后确认于
- 2025/12/02 12:30 3 个月前
思路
考对于所有操作离线,按照右边边界的大小排序。
对于每一个位置 ,记录 表示如果第 个位置到第 个位置的序列是否满足条件( 表示满足; 表示不满足。规定当 时 )。
显然,对于 中的合法序列个数位 到 中所有与的元素在 走到 时的历史总和。
然后就是历史和线段树的板子了。
可以使用矩阵乘法。
构造 分别当前节点表示历史和、但前和、总长度。
当要将 加到 上时将矩阵乘上:
当要将 中异或时:
然后用线段树维护即可。
代码
CPP#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=500005;
struct M//矩阵
{
ll a[3][3];
inline void mem()
{
a[0][0]=0;
a[1][0]=0;a[1][1]=0;
a[2][0]=0;a[2][1]=0;a[2][2]=0;
}
inline void init()
{
a[0][0]=1;
a[1][0]=0;a[1][1]=1;
a[2][0]=0;a[2][1]=0;a[2][2]=1;
}
inline M operator*(M b)
{
M ans;
ans.a[0][0]=1;
ans.a[1][0]=a[1][0]+a[1][1]*b.a[1][0];
ans.a[1][1]=a[1][1]*b.a[1][1];
ans.a[2][0]=a[2][0]+a[2][1]*b.a[1][0]+b.a[2][0];
ans.a[2][1]=a[2][1]*b.a[1][1]+b.a[2][1];
ans.a[2][2]=1;
return ans;
}
}A;
struct seg//线段树
{
ll b,a,len;
M t;//懒标记
}w[8*N];
struct E
{
int ne,to;
}e[N];
int he[N],idx,a[N],b[N],l[N],r[N];
ll ans[N];
inline void pushup(int u)//跟新节点信息
{
w[u].b=w[u<<1].b+w[u<<1|1].b;
w[u].a=w[u<<1].a+w[u<<1|1].a;
w[u].len=w[u<<1].len+w[u<<1|1].len;
}
inline void pushdown(int u)//懒标记下传
{
M t=w[u].t;w[u].t.init();
w[u<<1].t=w[u<<1].t*t;
w[u<<1|1].t=w[u<<1|1].t*t;
ll b,a;
b=w[u<<1].b+t.a[1][0]*w[u<<1].a+t.a[2][0]*w[u<<1].len;
a=t.a[1][1]*w[u<<1].a+t.a[2][1]*w[u<<1].len;
w[u<<1].b=b;w[u<<1].a=a;
b=w[u<<1|1].b+t.a[1][0]*w[u<<1|1].a+t.a[2][0]*w[u<<1|1].len;
a=t.a[1][1]*w[u<<1|1].a+t.a[2][1]*w[u<<1|1].len;
w[u<<1|1].b=b;w[u<<1|1].a=a;
}
void build(int u,int l,int r)
{
w[u].t.init();
if(l==r)
{
w[u].len=1;
return;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void mul(int u,int l,int r,int x,int y)//对于每一个节点乘上矩阵A
{
pushdown(u);
if(l>=x&&r<=y)
{
w[u].t=w[u].t*A;
w[u].b=w[u].b;
w[u].a=-w[u].a+w[u].len;
return;
}
int mid=(l+r)>>1;
if(mid>=x)mul(u<<1,l,mid,x,y);
if(mid<y)mul(u<<1|1,mid+1,r,x,y);
pushup(u);
}
ll get(int u,int l,int r,int x,int y)//得到区间历史和
{
pushdown(u);
if(l>=x&&r<=y)return w[u].b;
int mid=(l+r)>>1;ll sum=0;
if(mid>=x)sum+=get(u<<1,l,mid,x,y);
if(mid<y)sum+=get(u<<1|1,mid+1,r,x,y);
return sum;
}
void add(int x,int y)
{
e[++idx].ne=he[x];
e[idx].to=y;
he[x]=idx;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>l[i]>>r[i];
add(r[i],i);
}
build(1,1,n);
A.init();
for(int i=1;i<=n;i++)
{
A.a[1][1]=-1;A.a[2][1]=1;
mul(1,1,n,b[a[i]]+1,i);//异或
A.a[1][1]=1;A.a[2][1]=0;
A.a[1][0]=1;
pushdown(1);
w[1].t=w[1].t*A;
w[1].b=w[1].b+w[1].a;
w[1].a=w[1].a;//可以将全局操作放进主函数
A.a[1][0]=0;
b[a[i]]=i;//跟新last
for(int j=he[i];j;j=e[j].ne)
ans[e[j].to]=get(1,1,n,l[e[j].to],i);//处理询问
}
for(int i=1;i<=m;i++)cout<<ans[i]<<'\n';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...