BZOJ 3533 [Sdoi2014]向量集

Posted pncbf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3533 [Sdoi2014]向量集相关的知识,希望对你有一定的参考价值。

题外话:终于不再拖了啊...今天竟然有了友链...于是心情好就补了一篇[email protected][email protected]

Description

维护一个向量集合,在线支持以下操作:

"A x y":加入向量(x,y);

"Q x y l r":询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。集合初始时为空。(|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)

Input

输入的第一行包含整数N和字符s,分别表示操作数和数据类别;

接下来N行,每行一个操作,格式如上所述。

请注意s≠‘E‘时,输入中的所有整数都经过了加密。你可以使用以下程序

得到原始输入:

inline int decode (int x long long lastans) {

     return x ^ (lastans & Ox7fffffff);

}

function decode

begin

其中x为程序读入的数,lastans为之前最后一次询问的答案。在第一次询问之前,lastans=0

注:向量(x,y)和(z,W)的点积定义为xz+yw。

Output

对每个Q操作,输出一个整数表示答案。

Sample Input

6 A

A 3 2

Q 1 5 1 1

A 15 14

A 12 9

Q 12 8 12 15

Q 21 18 19 18

Sample Output

13

17

17

 

解释:解密之后的输入为

6 E

A 3 2

Q 1 5 1 1

A 2 3

A 1 4

Q 1 5 1 2

Q 4 3 2 3

HINT

1 < =N < =4×10^5

 

这道题...课上讲的第一道题(之前的第一题出了锅...),也不难想,大概就是线段树上静态维护凸包(话说动态的话这个数据范围是不是不可做?)。

 

首先是关于凸包(第一次写凸包...这个时候...大概已经没救了),比如读入的向量是(a,b),我们要在第L个到第R个向量里找到一个向量(x,y)使得ax*by最大。设最后答案是ans。

可以列出式子: ax+by=ans

两边同除 b   (a/b)x+y=ans/b

然后移项    y=-(a/b)x+ans/b

这样的话...比较显然...-(a/b)是已知的斜率,那么找ans最大的话,把b分情况讨论一下,如果b>=0,那么在y轴上的截距应该尽可能高,那么维护一个上凸壳,在上凸壳上找三分答案;如果b<0,那么在y轴上的截距应尽可能小,那么就在维护的下凸壳上三分答案。

 

之后对于每次查询的[l,r],用线段树维护,每个节点维护所属区间的上凸壳和下凸壳(把每个向量看成点),但是发现每次合并复杂度是O(区间长度),好像炸了...但是考虑每个叶子节点只会被修改一次,其他节点好像也可以?有一个很显然的结论,对于每个询问,一定不会去直接询问一个还没有覆盖满的区间节点。所以...就可以在这里优化了,只有我把这个区间填满的时候,才去合并他的两个子区间(这个过程要求O(区间长度),因为凸包有序)。

 

一些细节:每个节点维护凸包...貌似用vector比较方便吧...但是传参的时候记得加上&...

 

下面是代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<vector>
  6 using namespace std;
  7 struct point{
  8     long long x,y;
  9     friend point operator -(const point &a,const point &b){
 10         point ret;
 11         ret.x=a.x-b.x;
 12         ret.y=a.y-b.y;
 13         return ret;
 14     }
 15     friend long long operator *(const point &a,const point &b){
 16         long long ret=a.x*b.y-a.y*b.x;
 17         return ret;
 18     }
 19     friend long long operator ^(const point &a,const point &b){
 20         long long ret=a.x*b.x+a.y*b.y;
 21         return ret;
 22     }
 23     friend bool operator <(const point &a,const point &b){
 24         if(a.x==b.x) return a.y<b.y;
 25         return a.x<b.x;
 26     }
 27 }in;
 28 int decode(long long x,long long a){return x^(a&0x7fffffff);}
 29 vector<point>shang[1600010],xia[1600010];
 30 long long ans=0ll;
 31 char s[5],flg[5];
 32 int m,st,ed;
 33 void merges(vector<point> &lson,vector<point> &rson,vector<point> &pos){
 34     unsigned i=0,j=0,all=0;
 35     while(i!=lson.size()||j!=rson.size()){
 36         if(i==lson.size()) in=rson[j++];
 37         else if(j==rson.size()) in=lson[i++];
 38         else in=(lson[i]<rson[j])?lson[i++]:rson[j++];
 39         while(all>=2&&((pos[all-1]-pos[all-2])*(in-pos[all-2]))>=0) all--,pos.pop_back();
 40         all++,pos.push_back(in);
 41     }return;
 42 }
 43 void mergex(vector<point> &lson,vector<point> &rson,vector<point> &pos){
 44     unsigned i=0,j=0,all=0;
 45     while(i!=lson.size()||j!=rson.size()){
 46         if(i==lson.size()) in=rson[j++];
 47         else if(j==rson.size()) in=lson[i++];
 48         else in=(lson[i]<rson[j])?lson[i++]:rson[j++];
 49         while(all>=2&&((in-pos[all-2])*(pos[all-1]-pos[all-2]))>=0) all--,pos.pop_back();
 50         all++,pos.push_back(in);
 51     }return;
 52 }
 53 void insert(int l,int r,int pos){
 54     if(l==r){
 55         shang[pos].push_back(in);
 56         xia[pos].push_back(in);
 57         return;
 58     }
 59     int mid=(l+r)/2,lson=pos*2,rson=pos*2+1;
 60     if(m<=mid) insert(l,mid,lson);
 61     else insert(mid+1,r,rson);
 62     if(r==m) merges(shang[lson],shang[rson],shang[pos]),mergex(xia[lson],xia[rson],xia[pos]);
 63     return;
 64 }
 65 void sanfen(vector<point> &pos){
 66     int i,l=0,r=pos.size()-1,lmid,rmid;
 67     while(r-l>2){
 68         lmid=(l*2+r)/3,rmid=(l+r*2)/3;
 69         if((pos[lmid]^in)>(pos[rmid]^in)) r=rmid;
 70         else l=lmid;
 71     }
 72     for(i=l;i<=r;i++) ans=max(ans,(pos[i]^in));
 73     return;
 74 }
 75 void find(int l,int r,int pos){
 76     if(st<=l&&r<=ed){
 77         if(in.y>=0) sanfen(shang[pos]);
 78         else sanfen(xia[pos]);
 79         return;
 80     }
 81     int mid=(l+r)/2,lson=pos*2,rson=pos*2+1;
 82     if(st<=mid) find(l,mid,lson);
 83     if(mid<ed) find(mid+1,r,rson);
 84     return;
 85 }
 86 int read(){
 87     int ret=0;bool flag=false;char c=getchar();
 88     while(c<0||9<c){if(c==-) flag=true;c=getchar();}
 89     while(0<=c&&c<=9) ret=ret*10+c-0,c=getchar();
 90     return flag?-ret:ret;
 91 }
 92 int main()
 93 {
 94     int i,n,x,y;
 95     n=read();
 96     scanf("%s",flg);
 97     for(i=1;i<=n;i++){
 98         scanf("%s",s);
 99         if(s[0]==A){
100             x=read(),y=read();
101             if(flg[0]!=E){x=decode(x,ans),y=decode(y,ans);}
102             in.x=x,in.y=y,m++;
103             insert(1,n,1);
104         }
105         else{
106             x=read(),y=read(),st=read(),ed=read();
107             if(flg[0]!=E){x=decode(x,ans),y=decode(y,ans),st=decode(st,ans),ed=decode(ed,ans);}
108             in.x=x,in.y=y;ans=-4611686014132420609ll;
109             find(1,n,1);
110             printf("%lld\n",ans);
111         }
112     }
113     return 0;
114 }

 

以上是关于BZOJ 3533 [Sdoi2014]向量集的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3533: [Sdoi2014]向量集

BZOJ3533 [Sdoi2014]向量集 线段树 + 凸包 + 三分

BZOJ3533: [Sdoi2014]向量集

BZOJ 3533 sdoi 2014 向量集

[BZOJ3533]向量集

[SDOI2014] 向量集