Description
原题目名字是“我们仍未知道那天所看见的数据结构的名字”,由于原题目名太长就叫Unknown了……
我们,渐渐地长大了。在这缓缓逝去的季节里,屏幕上闪烁的字符,也在静静地变化着。
那个季节里编写的数据结构,叫什么名字来着呢?
慢慢地,OI渐渐地淡去。而我们则在不断成长,但是那个程序一定仍在某个时空里继续运行着。
Salroey忘了那个数据结构的名字和内容,但她却记得题目,于是她来寻求你的帮助。
有一个元素为向量的序列,下标从1开始,初始时为空,现在你需要支持三个操作:
1.在S的末尾添加一个元素(x,y)。
2.删除S的末尾元素。
3.询问下标在[l,r][l,r]区间内的元素中,(x,y)×Si的最大值。
其中××表示向量的叉积,(x1,y1)×(x2,y2)=x1y2−x2y1
Solution
由于 (1) 操作保证了向量一定是在 (x) 轴上方的
所以一定答案一定在凸包上,如果不是区间查询的话,维护一个凸包,然后三分就行了
如果有区间查询,用线段树维护就好了
对于每一个节点维护一个凸包,但是暴力合并复杂度是 (O(n)) 的
考虑一种神奇的做法....
由于这题点是在序列末端插入和在序列末端删除的
利用这个性质,我们可以等区间的点都满了再合并....但是可以在一个点附近反复横跳删除和添加
这样还是被卡了
所以用一个神奇的套路:
等该层的下一个节点满了再合并这个节点,这样的话,假设序列长度为 (k),那么每 (k) 次插入才会 (O(k)) 的合并一次,均摊是 (O(1)) 的....
复杂度 (O(n*log^2)),代码常数贼大...
#include<bits/stdc++.h>
#define ls (o<<1)
#define rs (o<<1|1)
using namespace std;
typedef long long ll;
const int N=524289,mod=998244353,M=1050000;
struct P{
int x,y;
inline ll operator *(const P b){return 1ll*x*b.y-1ll*b.x*y;}
inline bool operator <(const P b)const
{return x<b.x||(x==b.x && y<b.y);}
inline P operator -(const P b){return (P){x-b.x,y-b.y};}
}k;
vector<P>v[M];
int Q,T,op,pos=0,n=N-1,pre[25];
inline void upd(vector<P>&x,vector<P>&y,vector<P>&t){
int i=0,j=0,sx=x.size(),sy=y.size();P w;
while(i<sx || j<sy){
if(j==sy||(i<sx&&x[i]<y[j]))w=x[i++];
else w=y[j++];
while(t.size()>=2 && (w-t[t.size()-1])*(t[t.size()-1]-t[t.size()-2])<=0)
t.pop_back();
t.push_back(w);
}
}
inline void ins(int l,int r,int o,int sa,int t){
if(l==r){v[o].push_back(k);return ;}
int mid=(l+r)>>1;
if(sa<=mid)ins(l,mid,ls,sa,t+1);
else{
ins(mid+1,r,rs,sa,t+1);
if(sa==r){
if(pre[t])upd(v[pre[t]<<1],v[pre[t]<<1|1],v[pre[t]]);
pre[t]=o;
}
}
}
inline void Delet(int l,int r,int o,int sa,int t){
if(l==r){vector<P>().swap(v[o]);return ;}
int mid=(l+r)>>1;
if(sa<=mid)Delet(l,mid,ls,sa,t+1);
else{
Delet(mid+1,r,rs,sa,t+1);
if(sa==r)vector<P>().swap(v[o]),pre[t]=0;
}
}
inline ll midit(vector<P>&v){
int l=0,r=v.size()-1,ret=0,lm,rm;
while(l<=r){
lm=l+(r-l+1)/3;rm=r-(r-l)/3;
if(k*(v[lm]-v[rm])>=0)ret=lm,r=rm-1;
else ret=rm,l=lm+1;
}
return k*v[ret];
}
inline ll qry(int l,int r,int o,int sa,int se){
if(sa<=l && r<=se && !v[o].empty())return midit(v[o]);
int mid=(l+r)>>1;
if(se<=mid)return qry(l,mid,ls,sa,se);
else if(sa>mid)return qry(mid+1,r,rs,sa,se);
return max(qry(l,mid,ls,sa,mid),qry(mid+1,r,rs,mid+1,se));
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>T;
int x,y;
while(1){
int ans=0,pos=0;
scanf("%d",&Q);
if(Q==0)break;
for(int i=0;i<M;i++) vector<P>().swap(v[i]);
memset(pre,0,sizeof(pre));
while(Q--){
scanf("%d",&op);
if(op==1)scanf("%d%d",&k.x,&k.y),ins(1,n,1,++pos,0);
else if(op==2)Delet(1,n,1,pos--,0);
else scanf("%d%d%d%d",&x,&y,&k.x,&k.y),ans^=(qry(1,n,1,x,y)%mod+mod)%mod;
}
cout<<ans<<endl;
}
return 0;
}