• 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;
    }
    
    
  • 相关阅读:
    python数据分析实例(1)
    Latex学习(1): longtable的分页显示保留表头与标题L
    pl/sql学习(5): 触发器trigger/事务和锁
    pl/sql学习(6): 引号/程序调试/列中的字符串合并/正则表达式
    pl/sql学习(4): 包package
    SQL入门(4): 嵌入式SQL语言
    我觉得vue原理就是 Object.defineProperty,简单实现了set和get,谢谢
    vue组件一
    css3 flex盒子布局
    php连接数据库、创建数据库、创建数据表
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8516291.html
Copyright © 2020-2023  润新知