UOJ #191. 【集训队互测2016】Unknown

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;
}

posted @ 2018-04-13 20:14  PIPIBoss  阅读(541)  评论(0编辑  收藏  举报