【题解】[JOISC2020] 扫除

solution:

果不愧是 JOISC 毒瘤题。

正确的思考方式:

如果只有往右扫的操作,那么操作的顺序就不重要了,那么一个点往右移动只在于能包含它的最能往右的操作。

如果还有往上扫的操作,那么一个高度为 l l l 的往右扫的操作,实际上只能把还没扫除范围的点往右移,注意到被扫除范围的点一定是 [ 1 , x ] [1,x] [1,x] 范围内的点(可以通过按顺序操作线段树维护),那么这个右扫的实际作用范围就是横坐标为 [ x + 1 , n − l ] [x+1,n-l] [x+1,nl] 的点。

把所有横向操作的影响范围预处理出来后,那么对于横向的操作的顺序又不重要了,可以按照 h h h 排序后,区间取 m a x max max 然后对于每个灰尘单点查询 m a x max max 即可得到横坐标的变化。

可以得到 64 p t s 64pts 64pts 。(

引入算法:线段树分治(类比cdq的恶心玩意):

为了去掉插入,考虑线段树分治,对于每个查询拆分成 log 个整区间,套用上述做法即可。

朴素做法 O ( ( m + q ) log ⁡ q log ⁡ n ) O((m+q)\log q\log n) O((m+q)logqlogn) 。使用离散化坐标可以得到更优的复杂度。

#include<bits/stdc++.h> #define ll long long #define INF 0x3f3f3f3f #define PII pair<int,int> #define fi first #define se second #define vi vector<int> #define pb push_back using namespace std; const int N=2e6+5; int n,m,q,sum,rt[2],ap[N],ax[N],ay[N],lc[N<<5],rc[N<<5],mx[N<<5]; vi lp,rp,ty,le,ansx,ansy; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*f; } void clear() { rt[0]=rt[1]=sum=0; } bool cmpx(int x,int y) { return ansx[x]>ansx[y]; } bool cmpy(int x,int y) { return ansy[x]>ansy[y]; } void upd(int l,int r,int &pos,int L,int R,int x) { if(L>R) return; if(!pos) pos=++sum,lc[pos]=rc[pos]=mx[pos]=0; if(L<=l&&r<=R) return (void)(mx[pos]=max(mx[pos],x)); int mid=l+r>>1; if(L<=mid) upd(l,mid,lc[pos],L,R,x); if(R>mid) upd(mid+1,r,rc[pos],L,R,x); } int qry(int l,int r,int &pos,int x) { if(!pos) return 0; if(l==r) return mx[pos]; int mid=l+r>>1; //标记永久化 return max(mx[pos],x<=mid?qry(l,mid,lc[pos],x):qry(mid+1,r,rc[pos],x)); } void solve(int l,int r,const vi &qu) { if(qu.empty()) return; clear(); vi lq,rq,nq; vector<pair<int,int>> v[2]; int mid=l+r>>1; for(int i=l,t;i<=r;i++) { t=ty[i]; v[t].pb(make_pair(-le[i],qry(0,n,rt[t^1],le[i]))); upd(0,n,rt[t],v[t].back().se,n-le[i]-1,le[i]+1); } for(int i=0;i<qu.size();i++) { if(lp[qu[i]]<=l&&r<=rp[qu[i]]) { nq.pb(qu[i]); } else { if(lp[qu[i]]<=mid) lq.pb(qu[i]); if(rp[qu[i]]>mid) rq.pb(qu[i]); } } clear(); sort(v[0].begin(),v[0].end()); sort(nq.begin(),nq.end(),cmpy); for(int i=0,j=0;i<nq.size();i++) { for(;j<v[0].size()&&-v[0][j].fi>=ansy[nq[i]];j++) { upd(0,n,rt[0],v[0][j].se,n+v[0][j].fi,n+v[0][j].fi); } ansx[nq[i]]=max(ansx[nq[i]],qry(0,n,rt[0],ansx[nq[i]])); } sort(v[1].begin(),v[1].end()); sort(nq.begin(),nq.end(),cmpx); for(int i=0,j=0;i<nq.size();i++) { for(;j<v[1].size()&&-v[1][j].fi>=ansx[nq[i]];j++) { upd(0,n,rt[1],v[1][j].se,n+v[1][j].fi,n+v[1][j].fi); } ansy[nq[i]]=max(ansy[nq[i]],qry(0,n,rt[1],ansy[nq[i]])); } solve(l,mid,lq); solve(mid+1,r,rq); } signed main() { // freopen("data.in","r",stdin); // freopen("own.out","w",stdout); n=read(),m=read(),q=read(); for(int i=1;i<=m;i++) ax[i]=read(),ay[i]=read(); while(q--) { int op=read(),x=read(); if(op==1) lp.pb(ap[x]),rp.pb(ty.size()-1),ansx.pb(ax[x]),ansy.pb(ay[x]); else if(op==2) ty.pb(0),le.pb(x); else if(op==3) ty.pb(1),le.pb(x); else ax[++m]=x,scanf("%d",&ay[m]),ap[m]=ty.size(); } vi qu; for(int i=0;i<lp.size();i++) { if(lp[i]<=rp[i]) { qu.pb(i); } } solve(0,ty.size()-1,qu); for(int i=0;i<lp.size();i++) { printf("%d %d\n",ansx[i],ansy[i]); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530259.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(13)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示