题意:数组a刚开始全为0。给出n(数组a长度),m,X,Y,Z。
由X,Y,Z可以计算出m组(l,r,v):将区间(l,r)中小于v的数变为v
思路:
1.线段树维护区间最小值。区间更新,单点查询。
2.需要剪枝,如果当前区间的minn大于等于要更新的值可以直接返回。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
unsigned int x,y,z,w;
int n,m;
const int N=1e5+10;
const int M=3*5e6+10;
unsigned RNG()
{
x=x^(x<<11);
x=x^(x>>4);
x=x^(x<<5);
x=x^(x>>14);
w=x^(y^z);
x=y;
y=z;
z=w;
return z;
}
struct tree{
int l,r,minn,lazy;
}t[N*4];
void pushup(int x)
{
t[x].minn=min(t[x*2].minn,t[x*2+1].minn);//注意是min
}
void build(int x,int l,int r)
{
t[x].l=l;t[x].r=r;t[x].minn=0;t[x].lazy=0;
if(l==r)
{
return;
}
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
}
void pushdown(int x)
{
if(t[x].lazy)
{
t[x*2].minn=max(t[x*2].minn,t[x].lazy);
t[x*2].lazy=max(t[x*2].lazy,t[x].lazy);
t[x*2+1].minn=max(t[x*2+1].minn,t[x].lazy);
t[x*2+1].lazy=max(t[x*2+1].lazy,t[x].lazy);
}
}
void update(int x,int l,int r,int k)
{
if(t[x].minn>=k) return;//必要的剪枝
if(t[x].l>=l&&t[x].r<=r)
{
t[x].minn=max(t[x].minn,k);
t[x].lazy=max(t[x].lazy,k);
return;
}
pushdown(x);
int mid=(t[x].l+t[x].r)/2;
if(l<=mid) update(x*2,l,r,k);
if(r>mid) update(x*2+1,l,r,k);
pushup(x);
}
int query(int x,int k)
{
if(t[x].l==t[x].r)
{
return t[x].minn;
}
pushdown(x);
int mid=(t[x].l+t[x].r)/2;
if(k<=mid) return query(x*2,k);
else return query(x*2+1,k);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%u%u%u",&n,&m,&x,&y,&z);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int l,r,v;
unsigned f1=RNG();//必须是unsigned
unsigned f2=RNG();
unsigned f3=RNG();
l=min((f1%n)+1,(f2%n)+1);
r=max((f1%n)+1,(f2%n)+1);
v=f3%(1<<30);
update(1,l,r,v);
}
ll ans=0;
for(int i=1;i<=n;i++)
{
ans^=((ll)i*query(1,i));
}
printf("%lld\n",ans);
}
}
本文详细介绍了一种利用线段树进行区间更新和单点查询的算法实现,特别适用于处理数组中大量区间修改操作的问题。通过实例讲解了如何构建线段树、区间更新和查询的流程,以及如何通过剪枝优化算法效率。
547

被折叠的 条评论
为什么被折叠?



