UOJ#515. 【UR #19】前进四 离线+吉司机线段树

离线,然后从后向前扫描,维护每一个时刻当前位置的后缀最小值.

我们发现依次修改影响的是时间线段树一段区间要取 min,这个用吉司机线段树维护就好了.

具体地,我们记录一个 tag 标记,然后下传条件是 mx[now]<mx[lson] 或 mx[now]<mx[rson].   

这道题卡常,最好不要用 vector 来存储操作.     

code: 

#include <bits/stdc++.h>   
#define N 2000009  
#define ll long long 
#define lson now<<1 
#define rson now<<1|1  
#define inf 2000000009    
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)  
using namespace std;     
int n,m,Q;  
int mx[N<<2],se[N<<2],tag[N<<2],a[N];   
void pushup(int now) 
{
	mx[now]=max(mx[lson],mx[rson]);   
	if(mx[lson]==mx[rson]) se[now]=max(se[lson],se[rson]);   
	else if(mx[lson]<mx[rson]) se[now]=max(mx[lson],se[rson]);  
	else se[now]=max(mx[rson],se[lson]);  
}   
void pushdown(int now) 
{   
	if(mx[lson]>mx[now]) mx[lson]=mx[now],tag[lson]+=tag[now];   
	if(mx[rson]>mx[now]) mx[rson]=mx[now],tag[rson]+=tag[now];  
	tag[now]=0;  
}
void update(int l,int r,int now,int L,int R,int v) 
{
	if(mx[now]<=v) return;   
	if(l>=L&&r<=R&&se[now]<v) 
	{       
		mx[now]=v,++tag[now];  
		return;  
	}      
	pushdown(now);   
	int mid=(l+r)>>1;   
	if(L<=mid)  update(l,mid,lson,L,R,v);  
	if(R>mid)   update(mid+1,r,rson,L,R,v);  
	pushup(now);   
}   
int query(int l,int r,int now,int p) 
{
	if(l==r) return tag[now];            
	int mid=(l+r)>>1;    
	pushdown(now); 
	if(p<=mid) return query(l,mid,lson,p); 
	else return query(mid+1,r,rson,p);      
} 
void build(int l,int r,int now) 
{     
	mx[now]=inf,se[now]=-inf;    
	if(l==r) return;  
	int mid=(l+r)>>1;  
	build(l,mid,lson),build(mid+1,r,rson);  
}
int Ans[N];  
vector<int>q[N]; 
struct data 
{ 
	int x,t;  
	data(int x=0,int t=0):x(x),t(t){}   
	bool operator<(const data b) const { return t<b.t; }   
}er[N];
int hd[N],nex[N],edges;      
void add(int u,data e) 
{
	nex[++edges]=hd[u],hd[u]=edges,er[edges]=e;   
}           
char *p1,*p2,buf[100000];    
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)     
int rd() 
{ 
	int x=0; char c;  
	while(c<48) c=nc();   
	while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc();  
	return x;  
}    
int main() 
{ 
	// setIO("input");     
	int x,y,z;  
	n=rd(),m=rd();   
	for(int i=1;i<=n;++i)  a[i]=rd(),add(i,data(a[i],0));           
	for(int i=1;i<=m;++i) 
	{        
		x=rd();  
		if(x==1) y=rd(),z=rd(),add(y,data(z,i));    // z 时刻开始生效         
		if(x==2) y=rd(),q[y].push_back(i);   
	}         
	build(0,m,1);           
	for(int i=n;i>=1;--i) 
	{   
		int pr=m;  
		for(int j=hd[i];j;j=nex[j]) 
		{    
			data e=er[j];   
			int r=pr,l=e.t;              
			update(0,m,1,l,r,e.x);           
			pr=e.t-1;  
		}
		for(int j=0;j<q[i].size();++j)  Ans[q[i][j]]=query(0,m,1,q[i][j]);   
	}          
	for(int i=1;i<=m;++i) if(Ans[i]) printf("%d\n",Ans[i]);  
	return 0; 
}

  

posted @ 2020-06-08 16:10  EM-LGH  阅读(308)  评论(0编辑  收藏  举报