QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#152264 | #3554. Sweeping | OvO_Zuo | 0 | 0ms | 0kb | C++14 | 5.6kb | 2023-08-27 21:37:36 | 2023-08-27 21:37:38 |
Judging History
answer
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
const int N=1e6+5;
int n,m,q;
struct node{
int x,y;
node(int a=0,int b=0):x(a),y(b){}
}pos[N],ans[N],tmp[N];
int kk=0,cnt=0,sum,type[N],len[N],st[N],l[N],r[N];
struct segment
{
int kk,ls[N<<2],rs[N<<2],v[N<<2];
segment(){ kk=1;}
void clear(){ for(int i=0;i<=kk;i++) ls[i]=rs[i]=v[i]=0; kk=1;}
int modify(int l,int r,int tl,int tr,int vv,int idx)
{
if(!idx) idx=++kk;
if(l>=tl&&r<=tr)
{
v[idx]=max(v[idx],vv);
//cout<<"gai:"<<l<<" "<<r<<" "<<vv<<" "<<v[idx]<<endl;
return idx;
}
int mid=(l+r)>>1;
if(mid>=tl) ls[idx]=modify(l,mid,tl,tr,vv,ls[idx]);
if(mid<tr) rs[idx]=modify(mid+1,r,tl,tr,vv,rs[idx]);
//cout<<"modify:"<<kk<<" "<<l<<" "<<r<<" "<<idx<<" "<<ls[idx]<<" "<<rs[idx]<<endl;
return idx;
}
int query(int l,int r,int tar,int idx)
{
if(!idx) return 0;
//cout<<"query:"<<l<<" "<<r<<" "<<tar<<" "<<v[idx]<<endl;
if(l==r) return v[idx];
int mid=(l+r)>>1;
if(mid>=tar) return max(query(l,mid,tar,ls[idx]),v[idx]);
else return max(query(mid+1,r,tar,rs[idx]),v[idx]);
}
}tr[2];
namespace seg
{
vector<int> ask[N<<2];
void add(int l,int r,int tl,int tr,int id,int idx)
{
if(l>=tl&&r<=tr)
{
ask[idx].push_back(id);
return;
}
int mid=(l+r)>>1;
if(mid>=tl) add(l,mid,tl,tr,id,idx<<1);
if(mid<tr) add(mid+1,r,tl,tr,id,idx<<1|1);
}
void sol(int l,int r,int idx)
{
if(ask[idx].size())
{
int i,j,k;
tr[0].clear();
tr[1].clear();
vector<pii> ps[2];
for(i=l;i<=r;i++)
{
j=tr[type[i]].query(0,n,len[i],1);
ps[type[i]].push_back(mkp(j,len[i]));//,cout<<type[i]<<" "<<j<<" "<<len[i]<<endl;
//cout<<1-type[i]<<" "<<j<<" "<<n-len[i]-1<<" "<<len[i]+1<<endl;
tr[1-type[i]].modify(0,n,j,n-len[i]-1,len[i]+1,1);
}
for(i=0;i<ask[idx].size();i++) tmp[ask[idx][i]]=ans[ask[idx][i]];
sort(ask[idx].begin(),ask[idx].end(),[&](int a,int b){ return ans[a].x<ans[b].x;});
sort(ps[0].begin(),ps[0].end());
tr[0].clear();
i=0;
ps[0].push_back(mkp(n+1,0));
for(pii x:ps[0]){
while(i<ask[idx].size()&&x.fi>ans[ask[idx][i]].y){
tmp[ask[idx][i]].y=max(tmp[ask[idx][i]].y,tr[0].query(0,n,ans[ask[idx][i]].x,1));
++i;
}
tr[0].modify(0,n,0,x.se,n-x.se,1);
}
sort(ask[idx].begin(),ask[idx].end(),[&](int a,int b){ return ans[a].y<ans[b].y;});
sort(ps[1].begin(),ps[1].end());
tr[1].clear();
i=0;
ps[1].push_back(mkp(n+1,0));
for(pii x:ps[1]){
while(i<ask[idx].size()&&x.fi>ans[ask[idx][i]].x){
//cout<<tmp[ask[idx][i]].x<<" "<<ans[ask[idx][i]].y<<" "<<tr[1].query(0,n,ans[ask[idx][i]].y,1)<<endl;
tmp[ask[idx][i]].x=max(tmp[ask[idx][i]].x,tr[1].query(0,n,ans[ask[idx][i]].y,1));
++i;
}
//cout<<0<<" "<<x.fi<<" "<<x.se<<" "<<n-x.se<<endl;
tr[1].modify(0,n,0,x.se,n-x.se,1);
}
for(i=0;i<ask[idx].size();i++) ans[ask[idx][i]]=tmp[ask[idx][i]];
}
if(l==r) return;
int mid=(l+r)>>1;
sol(l,mid,idx<<1),sol(mid+1,r,idx<<1|1);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
int i,op,j,k;
for(i=1;i<=m;i++) scanf("%d%d",&pos[i].x,&pos[i].y),st[i]=0;
sum=m;
for(i=1;i<=q;i++)
{
scanf("%d",&op);
if(op==1)
{
++cnt;
scanf("%d",&j);
l[cnt]=st[j]+1;
r[cnt]=kk;
//cout<<cnt<<" "<<l[cnt]<<" "<<r[cnt]<<endl;
ans[cnt]=pos[j];
}
else if(op==4)
{
++sum;
scanf("%d%d",&pos[sum].x,&pos[sum].y);
st[sum]=kk;
}
else{
++kk;
scanf("%d",&len[kk]);
type[kk]=1-(op&1);
}
}
for(i=1;i<=cnt;i++)
seg::add(1,kk,l[i],r[i],i,1);
seg::sol(1,kk,1);
for(i=1;i<=cnt;i++)
printf("%d %d\n",ans[i].x,ans[i].y);
return 0;
}
/*
依次考虑所有部分分
只有124操作:
每次相当于一个区间取max
将所有操作离线后,按照x坐标升序重编号
4操作就是一次单点赋值,2操作就是区间取max
只有123操作且 x[i]<=x[i+1] && y[i]>=y[i+1]:
不论进行什么操作,x均不降,y均不升
于是将x,y分开维护
每次操作可以二分求出受到影响的区间并进行区间赋值
只有123操作:
此时的点不满足 x不降,y不减
但所有已经被操作过一次的点一定满足这一条件
于是,所有操作的影响区间可以只使用右上角表示
一个点第一次被操作,就是右上角被操作时间最小的
于是将操作按右上角的纵坐标降序,也将点按纵坐标降序扫描线得到每个点第一次被影响的操作
这样,每次操作仍然是一个区间取max
而第一次受到影响的点可以直接计算出新的位置然后进行单点赋值
也许需要使用平衡树维护?(因为 xy 都会变,所以不容易进行重编号)
无特殊约束:
只有123的方法不能用在这里,因为会有新加的点
假设先进行了一次纵向操作 x 后进行一次横向操作 y
那么也就是说,y只能对 (纵坐标 >x 且纵坐标 <=y 的点的横坐标) 与 (n-y) 取max
顺次考虑所有操作,不难发现,每个纵向操作,会对后于它的横向操作的下界有限制
使用两棵线段树维护两种操作的下界(将x,y分别离散化,vx[i]/vy[i]记录当前时刻下,x/y=i 的下界)
此时所有操作之间是独立的了
对于所有询问,找到该询问的点加入后的第一次操作和询问前的最后一次操作
我们可以认为该询问的答案只由该区间内的操作决定
这就意味着只要将该区间内的操作按下界从小到大排序后
按另一维排序维护线段树取max即可
使用线段树分治即可
*/
Details
Tip: Click on the bar to expand more detailed information
Subtask #1:
score: 0
Runtime Error
Test #1:
score: 0
Runtime Error
input:
999999999 2000 5000 406191928 499382196 562579162 405324970 758918451 226610082 56425557 481714604 280111172 204083332 178122667 423322594 656895843 125933171 283229448 255332800 375268656 368221716 287124150 218833686 67804037 252992256 736660159 61831334 50624783 762562411 127286172 739867871 2174...
output:
result:
Subtask #2:
score: 0
Runtime Error
Test #7:
score: 0
Runtime Error
input:
1000000000 500000 1000000 565671866 434313351 151160620 848839277 759673958 240326022 747919325 251939968 652216454 341792707 697972826 302025968 437943290 562056699 963595717 25130832 833492450 163447023 453783218 546216655 852488265 147511733 364464144 334147914 493873353 504061372 104992045 86556...
output:
result:
Subtask #3:
score: 0
Runtime Error
Test #14:
score: 0
Runtime Error
input:
1000000000 499999 1000000 1603 999995752 1621 999984188 3408 999983654 3743 999979285 3830 999978594 5050 999974201 7426 999970241 13957 999962424 14611 999962335 16341 999954169 20684 999953545 21401 999952737 25492 999948443 25736 999946928 26128 999941492 29341 999937495 29753 999929827 33929 999...
output:
result:
Subtask #4:
score: 0
Skipped
Dependency #3:
0%
Subtask #5:
score: 0
Skipped
Dependency #1:
0%