• [BZOJ 4311] 向量


    一、题目

    点此看题

    二、解法

    线段树分治可以解决在线插入难,在线删除难,回退难的问题。

    就好比我们只会凸包的离线插入,那么在线段树上的每一个节点上维护一个凸包,然后去更新它管辖区间的所有询问即可,每个询问只会被更新 (log) 次所以复杂度是对的。

    忘了说这道题为什么要用凸包了,对于询问 ((x,y)) 考虑两个向量 ((x_1,y_1),(x_2,y_2)),设 (x_1<x_2),那么第二个向量比第一个向量更优的条件是:

    [xx_1+yy_1<xx_2+yy_2 ]

    [frac{-y_2+y_1}{x_2-x_1}<frac{x}{y} ]

    这相当于维护一个 ((x_i,-y_i)) 的下凸包,然后找第一个斜率大于等于 (frac{x}{y}) 的线段即可。

    实现细节:以总操作个数来建线段树,避免以询问个数来建线段树的细节,如果你调不出来就暴力访问凸包上的每个点,然后发现可以直接过掉。

    #include <cstdio>
    #include <vector>
    #include <cassert>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int M = 2000005;
    #define db double
    #define ll long long 
    #define int long long
    int read()
    {
        int x=0,f=1;char c;
        while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
        while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
        return x*f;
    }
    int n,m,k,tp,vx[M],vy[M],vl[M],vr[M],qx[M],qy[M],id[M];
    vector<int> p[4*M];ll nx,ny,ans[M];int v[M];db kk[M];
    void ins(int i,int l,int r,int L,int R,int x)
    {
    	if(L>r || l>R) return ;
    	if(L<=l && r<=R)
    	{
    		p[i].push_back(x);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	ins(i<<1,l,mid,L,R,x);
    	ins(i<<1|1,mid+1,r,L,R,x);
    }
    int cmp(int x,int y)
    {
    	return vx[x]==vx[y]?vy[x]<vy[y]:vx[x]<vx[y];
    }
    db slope(int x,int y)
    {
    	return 1.0*(vy[x]-vy[y])/(vx[y]-vx[x]);
    }
    void work(int x)
    {
    	tp=0;
    	sort(p[x].begin(),p[x].end(),cmp);
    	for(int i=0,sz=p[x].size();i<sz;i++)
    	{
    		int t=p[x][i];
    		while(tp>1 && slope(v[tp],t)
    		<=slope(v[tp-1],v[tp])) tp--;
    		v[++tp]=t;
    	}
    	v[tp+1]=0;
    	for(int i=1;i<tp;i++)
    		kk[i]=slope(v[i],v[i+1]);
    }
    ll dot(int x)
    {
    	return vx[x]*nx+vy[x]*ny;
    }
    void zxy(int x)
    {
    	nx=qx[x];ny=qy[x];
    	int t=lower_bound(kk+1,kk+tp,1.0*nx/ny)-kk;
    	//for(int i=1;i<=tp;i++)
    	//	ans[x]=max(ans[x],dot(v[i]));
    	if(t>tp) return ;
    	ans[x]=max(ans[x],dot(v[t]));
    	ans[x]=max(ans[x],dot(v[t-1]));
    	ans[x]=max(ans[x],dot(v[t+1]));
    	//return max(dot(v[t]),dot(v[t+1]));
    }
    void build(int i,int l,int r)
    {
    	work(i);
    	for(int i=l;i<=r;i++)
    		if(id[i]) zxy(id[i]);
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	build(i<<1,l,mid);
    	build(i<<1|1,mid+1,r);
    }
    signed main()
    {
    	//freopen("1.in","r",stdin);
    	//freopen("zxy.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		int t=read();
    		if(t==1)
    		{
    			m++;vl[m]=i;
    			vx[m]=read();vy[m]=read();
    		}
    		if(t==2)
    			vr[read()]=i;
    		if(t==3)
    			qx[++k]=read(),qy[k]=read(),id[i]=k;
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(vr[i]==0) vr[i]=n;
    		ins(1,1,n,vl[i],vr[i],i);
    	}
    	build(1,1,n);
    	for(int i=1;i<=k;i++)
    		printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    webpackHotMiddleware改造成koa支持的中间件
    webpack-dev-middleware改造成koa中件间
    Vue3学习笔记
    当前工程中typescritpt依赖包与依赖包中依赖包类型不一致如何解决
    typescript中使用Object.keys
    获取东8区时间
    SyntaxError: Invalid regular expression: invalid group specifier name
    测试代码框
    ST Lab2 Selenium
    ST HW3
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15187944.html
Copyright © 2020-2023  润新知