给定一个序列 { a n } \{a_n\} {an},有 m m m 次操作,形如 l r v
,表示将 [ l , r ] [l,r] [l,r] 的每个 a i a_i ai 变为 max ( a i , v ) \max(a_i,v) max(ai,v)。求最终的序列。
n ≤ 1 0 5 , m ≤ 1 0 7 n\le10^5,m\le10^7 n≤105,m≤107
考虑构建 ST 表的反过程,每次操作就给 st[l][x]
和 st[r-(1<
然后对于区间 [ i , i + 2 j + 1 ) [i,i+2^{j+1}) [i,i+2j+1),把区间分成两部分 [ i , i + 2 j ) [i,i+2^{j}) [i,i+2j) 和 [ i + 2 j , i + 2 j + 1 ) [i+2^j,i+2^{j+1}) [i+2j,i+2j+1),把 st[i][j+1]
往下更新即可。
时间复杂度 O ( n log n + m ) O(n\log n+m) O(nlogn+m)。
#include
using namespace std;
const int N=1e5+10;
int n,m,typ;
unsigned int a[N],bj[N],tr[N][18],lg[N];
namespace Maker{
unsigned int x0,seed;
void init() {scanf("%u%u",&x0,&seed);}
inline unsigned int getnum(){
x0=(x0<<3)^x0;
x0=((x0>>5)+seed)^x0;
return x0;
}
}
void update(int l,int r,unsigned int val)
{
int x=lg[r-l+1];
tr[l][x]=max(tr[l][x],val);
tr[r-(1<<x)+1][x]=max(tr[r-(1<<x)+1][x],val);
}
int main()
{
freopen("train.in","r",stdin);
freopen("train.out","w",stdout);
scanf("%d%d%d",&n,&m,&typ);
for(int i=1;i<=n;i++) scanf("%u",&a[i]);
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
Maker::init();
for(int i=1; i<=m; ++i){
int l=Maker::getnum()%n+1,r=Maker::getnum()%n+1;
unsigned int v=Maker::getnum();
if(l>r) swap(l,r);
if(typ==1) l=1;
update(l,r,v);
}
for(int j=16;j>=0;j--){
for(int i=1;i+(1<<j)<=n;i++){
tr[i][j]=max(tr[i][j],tr[i][j+1]);
tr[i+(1<<j)][j]=max(tr[i+(1<<j)][j],tr[i][j+1]);
}
}
for(int i=1;i<=n;i++) printf("%u ",max(a[i],tr[i][0]));
}
考虑用 t i t_i ti 记录所有左端点为 i i i 的操作区间的右端点。从小到大遍历 i i i,每次给 t i t_i ti 的所有右端点所在出打上标记 v v v。
一旦标记出现,标记的意义就是更新它左边所有的数,所以只需求 [ i , n ] [i,n] [i,n] 的标记的最大值,用分块可以解决。具体实现上,打标记时可以用 bj1
记录散块的标记,bj2
记录整块的标记,查询时若当前是散块,就用 bj1
更新,当前是整块,就用 bj2
更新。
为什么不用线段树求最大值?因为修改很多,我们想要保证修改 O ( 1 ) O(1) O(1),线段树做不到。
时间复杂度 O ( n n + m ) O(n\sqrt n+m) O(nn+m)
#include
using namespace std;
const int N=1e5+10;
int n,m,typ,block;
unsigned int a[N],bj1[N],bj2[400];
vector<pair<int,unsigned int> > v[N];
namespace Maker{
unsigned int x0,seed;
void init() {scanf("%u%u",&x0,&seed);}
inline unsigned int getnum(){
x0=(x0<<3)^x0;
x0=((x0>>5)+seed)^x0;
return x0;
}
}
void update(pair<int,unsigned int> a)
{
bj1[a.first]=max(bj1[a.first],a.second);
int id=(a.first-1)/block;
bj2[id]=max(bj2[id],a.second);
}
unsigned int getans(int l,int r)
{
int minr=min((l-1)/block*block+block,r),id=(l-1)/block;
unsigned int ans=0;
while(l<=minr){
ans=max(ans,bj1[l]);
l++;
}
while(r-l+1>=block){
ans=max(ans,bj2[(l-1)/block]);
l+=block;
}
while(l<=r){
ans=max(ans,bj1[l]);
l++;
}
return ans;
}
int main()
{
freopen("train.in","r",stdin);
freopen("train.out","w",stdout);
scanf("%d%d%d",&n,&m,&typ);
block=sqrt(n);
for(int i=1;i<=n;i++) scanf("%u",&a[i]);
Maker::init();
for(int i=1;i<=m;++i){
int l=Maker::getnum()%n+1,r=Maker::getnum()%n+1;
unsigned int val=Maker::getnum();
if(l>r) swap(l,r);
if(typ==1) l=1;
v[l].push_back(make_pair(r,val));
}
for(int i=1;i<=n;i++){
for(auto j:v[i]) update(j);
printf("%u ",max(a[i],getans(i,n)));
}
}