solution:
果不愧是 JOISC 毒瘤题。
正确的思考方式:
如果只有往右扫的操作,那么操作的顺序就不重要了,那么一个点往右移动只在于能包含它的最能往右的操作。
如果还有往上扫的操作,那么一个高度为
l
l
l 的往右扫的操作,实际上只能把还没扫除范围的点往右移,注意到被扫除范围的点一定是
[
1
,
x
]
[1,x]
[ 1 , x ] 范围内的点(可以通过按顺序操作线段树维护),那么这个右扫的实际作用范围就是横坐标为
[
x
+
1
,
n
−
l
]
[x+1,n-l]
[ x + 1 , n − l ] 的点。
把所有横向操作的影响范围预处理出来后,那么对于横向的操作的顺序又不重要了,可以按照
h
h
h 排序后,区间取
m
a
x
max
m a x 然后对于每个灰尘单点查询
m
a
x
max
m a x 即可得到横坐标的变化。
可以得到
64
p
t
s
64pts
6 4 p t s 。(
引入算法:线段树分治 (类比cdq的恶心玩意):
为了去掉插入,考虑线段树分治,对于每个查询拆分成 log 个整区间,套用上述做法即可。
朴素做法
O
(
(
m
+
q
)
log
q
log
n
)
O((m+q)\log q\log n)
O ( ( m + q ) log q log n ) 。使用离散化坐标可以得到更优的复杂度。
#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 () {
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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」