3533: [Sdoi2014]向量集
Time Limit: 25 Sec Memory Limit: 512 MB
Submit: 669 Solved: 213
Description
维护一个向量集合,在线支持以下操作:
"A x y (|x|,|y| < =10^8)":加入向量(x,y);
" Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
集合初始时为空。
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
新加数据一组..2015.315
Source
线段树+凸包+三分,思路好题
有一个结论:答案一定会出现在凸包上,而且如果y>0则在上凸包上,否则在下凸包上。
具体证明我不太会…分享一个链接:http://blog.csdn.net/u012288458/article/details/50957363
然后在一个凸包上答案是单峰的,可以用三分来做。
于是问题就变成了如何动态维护区间的凸包,这个可以用线段树。
可是问题在于每次新加一个点会修改logn段区间,而凸包合并是O(n),显然这个复杂度不能接受。
有一个比较巧妙的解决方法,包含未插入位置的线段树节点一定不会被访问(这显然),所以每插入一个点x,只要将区间右端点是x的凸包合并就可以了。
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<vector> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 400005 #define inf 1000000000000000000ll using namespace std; int n,tot; ll ans; struct P { ll x,y; P(ll xx=0,ll yy=0){x=xx;y=yy;} friend P operator +(P a,P b){return P(a.x+b.x,a.y+b.y);} friend P operator -(P a,P b){return P(a.x-b.x,a.y-b.y);} friend ll operator *(P a,P b){return a.x*b.y-a.y*b.x;} friend ll operator ^(P a,P b){return a.x*b.x+a.y*b.y;} friend bool operator <(P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;} }; vector<P> a[maxn*4],b[maxn*4]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline int decode(int x){return x^(ans&0x7fffffff);} void merge_a(vector<P> &h1,vector<P> &h2,vector<P> &h) { vector<P>::iterator i=h1.begin(),j=h2.begin(); int top=0;P p; while (i!=h1.end()||j!=h2.end()) { if (i==h1.end()) p=*(j++); else if (j==h2.end()) p=*(i++); else p=*i<*j?*(i++):*(j++); while (top>=2&&(h[top-1]-h[top-2])*(p-h[top-2])>=0) h.pop_back(),top--; h.push_back(p);top++; } } void merge_b(vector<P> &h1,vector<P> &h2,vector<P> &h) { vector<P>::iterator i=h1.begin(),j=h2.begin(); int top=0;P p; while (i!=h1.end()||j!=h2.end()) { if (i==h1.end()) p=*(j++); else if (j==h2.end()) p=*(i++); else p=*i<*j?*(i++):*(j++); while (top>=2&&(h[top-1]-h[top-2])*(p-h[top-2])<=0) h.pop_back(),top--; h.push_back(p);top++; } } ll sanfen(vector<P> &h,P p)//这里不加& 会TLE { int l=0,r=h.size()-1,lmid,rmid; while (r-l>2) { lmid=(l*2+r)/3;rmid=(l+r*2)/3; if ((h[lmid]^p)>(h[rmid]^p)) r=rmid; else l=lmid; } ll ret=-inf; F(i,l,r) ret=max(ret,(h[i]^p)); return ret; } void insert(int k,int l,int r,int pos,P p) { if (l==r) { a[k].push_back(p); b[k].push_back(p); return; } int mid=(l+r)>>1; if (pos<=mid) insert(k<<1,l,mid,pos,p); else insert(k<<1|1,mid+1,r,pos,p); if (r==pos) { merge_a(a[k<<1],a[k<<1|1],a[k]); merge_b(b[k<<1],b[k<<1|1],b[k]); } } ll query(int k,int l,int r,int L,int R,P p) { if (l==L&&r==R) return p.y>0?sanfen(a[k],p):sanfen(b[k],p); int mid=(l+r)>>1; if (R<=mid) return query(k<<1,l,mid,L,R,p); if (L>mid) return query(k<<1|1,mid+1,r,L,R,p); return max(query(k<<1,l,mid,L,mid,p),query(k<<1|1,mid+1,r,mid+1,R,p)); } int main() { char flg[10],opt[10]; n=read();scanf("%s",flg); F(i,1,n) { scanf("%s",opt); if (opt[0]=='A') { int x=read(),y=read(); if (flg[0]!='E') x=decode(x),y=decode(y); insert(1,1,n,++tot,P(x,y)); } else { int x=read(),y=read(),l=read(),r=read(); if (flg[0]!='E') x=decode(x),y=decode(y),l=decode(l),r=decode(r); printf("%lld\n",ans=query(1,1,n,l,r,P(x,y))); } } return 0; }