! JOISC2020DAY1扫除

问题拆解,好题&难题



发现:每个点经历了一次修改后,若\(x_i<x_j\)\(y_i>y_j\)(貌似并没有用到?)

考虑线段树分治:

每个询问记录修改时间区间

每个时间段的区间将询问的点按\(x\)\(y\)排序

用动态开点线段树维护最大值算出每个修改的区间

\(H\)操作,在长度小于\(l\)的区域,可能会被\(V\)操作扫走,所以每次\(V\)操作,将\(n-l_v-1\)以内的区域都与\(l_v\)\(max\),这样就可以把两种操作分开进行,修改答案

加入点无影响

时间复杂度\(O(nlog_n^2)\)

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
#define pai pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define pb push_back 
#define vi vector<int> 
const int N=1600004;
int n,m,Q,qn,tim,tot;
int a[N][3],b[N][3],c[N][2],ans[N][2];
int t[N<<5],lc[N<<5],rc[N<<5],rt[2];
vector<pai>mv[2];
inline int newnode(){
	++tot;
	lc[tot]=rc[tot]=t[tot]=0;
	return tot;
}
void modify(int &p,int l,int r,int ql,int qr,int k){
	if(ql>qr||qr<0||ql>n)return;
	if(!p)p=newnode();
	if(ql<=l&&r<=qr){t[p]=max(t[p],k);return;}
	int mid=l+r>>1;
	if(ql<=mid)modify(lc[p],l,mid,ql,qr,k);
	if(mid<qr)modify(rc[p],mid+1,r,ql,qr,k);
}
int query(int p,int l,int r,int x){
	if(!p)return 0;
	if(l==r)return t[p];
	int mid=l+r>>1;
	if(x<=mid)return max(t[p],query(lc[p],l,mid,x));
	else return max(t[p],query(rc[p],mid+1,r,x));
}
inline void mdf(int op,int len){//找每次操作可以修改的区域 
	int t=query(rt[op^1],0,n,len);
	mv[op].pb(mp(len,t));
	modify(rt[op],0,n,t,n-len-1,len+1);
}
inline bool cmp0(int x,int y){
	return ans[x][1]>ans[y][1];
}
inline bool cmp1(int x,int y){
	return ans[x][0]>ans[y][0];
}
inline void solve(int l,int r,vi w){
	if(l>r)return;
	vi lw,rw,tmp;
	int mid=l+r>>1,ql,qr,j,x,y;
	for(auto i:w){
		ql=b[i][1];qr=b[i][2];
		if(ql<=l&&r<=qr)tmp.pb(i);
		else{
			if(ql<=mid)lw.pb(i);
			if(mid<qr)rw.pb(i);
		}
	}
	rt[0]=rt[1]=tot=0;
	mv[0].clear();mv[1].clear();
	for(int i=l;i<=r;i++)mdf(c[i][0],c[i][1]);
	sort(tmp.begin(),tmp.end(),cmp0);
	sort(mv[0].begin(),mv[0].end(),greater<pai>());
	rt[0]=tot=j=0;
	for(auto i:tmp){
		x=ans[i][0];y=ans[i][1];
		for(;j<mv[0].size()&&mv[0][j].fi>=y;j++){
			modify(rt[0],0,n,mv[0][j].se,n-mv[0][j].fi,n-mv[0][j].fi);
		}
		ans[i][0]=max(x,query(rt[0],0,n,x));
	}
	sort(tmp.begin(),tmp.end(),cmp1);
	sort(mv[1].begin(),mv[1].end(),greater<pai>());
	rt[1]=tot=j=0;
	for(auto i:tmp){
		x=ans[i][0];y=ans[i][1];
		for(;j<mv[1].size()&&mv[1][j].fi>=x;j++){
			modify(rt[1],0,n,mv[1][j].se,n-mv[1][j].fi,n-mv[1][j].fi);
		}
		ans[i][1]=max(y,query(rt[1],0,n,y));
	}
	if(l==r)return;
	solve(l,mid,lw);solve(mid+1,r,rw);
}
int main(){
	n=read();m=read();Q=read();
	for(int i=1;i<=m;i++){
		a[i][0]=read();a[i][1]=read();
		a[i][2]=1;
	}
	for(int i=1,op,x;i<=Q;i++){
		op=read();
		if(op==1){
			b[++qn][0]=x=read();b[qn][1]=a[x][2];
			b[qn][2]=tim;
		} 
		else if(op==2){
			c[++tim][1]=read();
		}
		else if(op==3){
			c[++tim][0]=1;c[tim][1]=read();
		}
		else{
			a[++m][0]=read();a[m][1]=read();
			a[m][2]=tim+1;
		}
	}
	vi vec;
	for(int i=1,x;i<=qn;i++){
		x=b[i][0];
		ans[i][0]=a[x][0];ans[i][1]=a[x][1];
		if(b[i][1]<=b[i][2])vec.pb(i); 
	}
	solve(1,tim,vec);
	for(int i=1;i<=qn;i++)
		cout<<ans[i][0]<<" "<<ans[i][1]<<"\n";
	return (0-0);
}
posted @ 2020-03-23 15:08  starusc  阅读(591)  评论(0)    收藏  举报