题:
bzoj3330
bzoj3203YES
bzoj3533YES
bzoj3874
bzoj1857YES
bzoj1229YES
bzoj3533☆
题意:
维护一个向量集合,在线支持以下操作:
"Axy(|x|,|y|≤108)"
:加入向量(x,y);
"Qxylr(|x|,|y|≤108,1≤L≤R≤T
,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
集合初始时为空。
分析:
设询问点为
(x,y)
,对应答案最大的点为
(x0,y0)
。
首先
(x0,y0)
一定在区间
[l,r]
区间中所有点的凸包上。且
当
y≥0
时
(x0,y0)
在上凸壳上
当
y<0
时
(x0,y0)
在下凸壳上
那么用线段树维护一下区间,但假如每次插入都更新凸包的话时间就爆炸了。发现如果区间右端点还没插入时这整段区间是不会查询的。于是乎只有插入区间右端点是才更新整个区间的上下凸壳。嗯~时间复杂度就是
O(nlog2n)
了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
typedef long long LL;
const LL inf=21333333333333333;
const int N=1048576;
int n,m,x,y,l,r,v[N],size;
long long lastans,ans;
struct node{int x,y,l,r,op;}g[N];
char s[N],tt[N];
struct point{
LL x,y;
point(){}
point(int _x,int _y):x(_x),y(_y){}
friend point operator - (point a,point b){
return point(a.x-b.x,a.y-b.y);
}
friend point operator + (point a,point b){
return point(a.x+b.x,a.y+b.y);
}
friend LL operator * (point a,point b){
return a.x*b.y-a.y*b.x;
}
friend LL operator ^ (point a,point b){
return a.x*b.x+a.y*b.y;
}
friend bool operator < (point a,point b){
if (a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}
}p[N],t[N];
struct range{
point *up,*dw;
int ut,dt;
void gao(int l,int r){
up=new point[r-l+2];
dw=new point[r-l+2];
int top=0;ut=dt=0;
for (int i=l;i<=r;i++)
t[++top]=p[i];
sort(t+1,t+top+1);
for (int i=1;i<=top;i++){
while (ut>1 && (t[i]-up[ut])*(up[ut]-up[ut-1])<=0) ut--;
up[++ut]=t[i];
while (dt>1 && (dw[dt]-dw[dt-1])*(t[i]-dw[dt])<=0) dt--;
dw[++dt]=t[i];
}
}
LL query(point k){
LL res=-inf;
if (k.y>=0){
int l=1,r=ut;
while (r-l>2){
int ll=l+(r-l)/3;
int rr=r-(r-l)/3;
if ((up[ll]^k)<(up[rr]^k))
l=ll; else r=rr;
}
for (int i=l;i<=r;i++)
res=max(res,up[i]^k);
} else {
int l=1,r=dt;
while (r-l>2){
int ll=l+(r-l)/3;
int rr=r-(r-l)/3;
if ((dw[ll]^k)<(dw[rr]^k))
l=ll; else r=rr;
}
for (int i=l;i<=r;i++)
res=max(res,dw[i]^k);
}
return res;
}
}tree[N];
LL query(int rt,int l,int r,int ll,int rr,point k){
if (ll<=l && r<=rr){
if (!v[rt]) tree[rt].gao(l,r);
v[rt]=1;return tree[rt].query(k);
}
int mid=(l+r)>>1;LL res=-inf;
if (ll<=mid) res=max(res,query(2*rt,l,mid,ll,rr,k));
if (rr> mid) res=max(res,query(2*rt+1,mid+1,r,ll,rr,k));
return res;
}
int read(){
int res=0,f=1;char c=getchar();
while(!isdigit(c))f=f==-1||c=='-'?-1:1,c=getchar();
while(isdigit(c))res=res*10+c-'0',c=getchar();
return (res*f);
}
int gao(){return lastans&0x7fffffff;}
int main(){
freopen("a.in","r",stdin);
scanf("%d%s",&m,s);
for (int i=1;i<=m;i++){
scanf("%s",tt);
if (tt[0]=='A'){
x=read();y=read();
g[i].x=x;g[i].y=y;
g[i].op=1;n++;
} else {
x=read();y=read();
l=read();r=read();
g[i].x=x;g[i].y=y;
g[i].l=l;g[i].r=r;
g[i].op=2;
}
}
for (int i=1;i<=m;i++){
if (g[i].op==1){
x=g[i].x;y=g[i].y;
if (s[0]!='E'){
x^=gao();y^=gao();
}
p[++size]=point(x,y);
} else {
x=g[i].x;y=g[i].y;
l=g[i].l;r=g[i].r;
if (s[0]!='E'){
x^=gao();y^=gao();
l^=gao();r^=gao();
}
lastans=query(1,1,n,l,r,point(x,y));
printf("%lld\n",lastans);
}
}
}
bzoj1857
三分套三分~就是分别三分两线段。
证明:http://blog.youkuaiyun.com/geotcbrl/article/details/48833339
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double p,q,len,ans;
const double eps=0.00000001;
struct node{
double x,y;
node(){}
node(double _x,double _y):x(_x),y(_y){}
friend double dis(node a,node b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
friend node operator - (node a,node b){
return node(a.x-b.x,a.y-b.y);
}
friend node operator + (node a,node b){
return node(a.x+b.x,a.y+b.y);
}
friend node operator / (node a,double x){
return node(a.x/x,a.y/x);
}
}a,b,c,d;
double find(node a){
node l=c,r=d;
double res=min(dis(a,r)/len,(dis(a,l)+dis(l,r))/len);
while (dis(l,r)>eps){
node ll=l+(r-l)/3.0;
node rr=r-(r-l)/3.0;
double t1=dis(d,ll)/q,t2=dis(d,rr)/q;
t1+=dis(ll,a)/len,t2+=dis(rr,a)/len;
if (t1<t2)
res=min(res,t1),r=rr; else
res=min(res,t2),l=ll;
}
return res;
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
scanf("%lf%lf%lf%lf",&c.x,&c.y,&d.x,&d.y);
scanf("%lf%lf%lf",&p,&q,&len);
node l=a,r=b;ans=min(find(a),dis(l,r)/p+find(b));
while (dis(l,r)>eps){
node ll=l+(r-l)/3.0;
node rr=r-(r-l)/3.0;
double t1=dis(a,ll)/p,t2=dis(a,rr)/p;
double r1=find(ll),r2=find(rr);
r1+=t1;r2+=t2;
if (r1<r2)
ans=min(ans,r1),r=rr; else
ans=min(ans,r2),l=ll;
}
printf("%.2lf\n",ans);
}
bzoj1229
若天数少的话就可以用费用流水掉了。
不然就贪心乱搞。
显然能去慢洗肯定比去快洗好(快洗比慢洗贵)。
现在问题来了,我们究竟要多少玩具捏。三分一波一开始的玩具个数(不会证明)然后在贪心乱搞一下就好了。
int gao(int x){
sl.clear();qk.clear();tm.clear();
int res=x*(tc-c2);
sl.push_back(node(0,x));
for (int i=1;i<=d;i++){
while (!tm.empty() && i-tm.front().x>=n1)
qk.push_back(tm.front()),tm.pop_front();
while (!qk.empty() && i-qk.front().x>=n2)
sl.push_back(qk.front()),qk.pop_front();
int T=t[i];
while (T){
if (!sl.empty()){
if (sl.back().c>=T){
sl.back().c-=T;
res+=T*c2;T=0;
} else {
T-=sl.back().c;
res+=sl.back().c*c2;
sl.pop_back();
}
} else
if (!qk.empty()){
if (qk.back().c>=T){
qk.back().c-=T;
res+=T*c1;T=0;
} else {
T-=qk.back().c;
res+=qk.back().c*c1;
qk.pop_back();
}
} else return inf;
}
tm.push_back(node(i,t[i]));
}
return res;
}