cf678F(时间线段树+凸包+三分)

解法:时间线段树+凸包+三分

一开始本来想的是:cdq分治+李超线段树(因为之前学长在湘潭ccpc的时候给我嘴过一个类似的)

后来发现我的做法要对于每个分治区间开一棵李超线段树肯定mle

以时间为轴建立线段树,表示某个点(x,y)存在的时间

对于线段树的每个节点上的若干(x,y)维护一个上凸壳;

对于每个询问,从根一路访问到所在的叶子节点,对于途中每经过的一个节点,在其上的凸壳上三分一个最大值来更新ans;

访问完若ans=-inf则说明该询问之前没有加点,输出EMPTY SET,否则ans就是答案

注意:

1.叉积会爆longlong,要用double存

2.ans的初值应该赋值成-2e18,因为最后可行的ans会是-1e18

3.三分的暴力区间不能过小(开始赋了5,wa到怀疑人生)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstring>
#include <string>
#include <vector>
#define lch a[n].lc
#define rch a[n].rc
#define pb push_back
#define er pop_back
using namespace std;
const long long inf=2e18;
const int maxn=500010;
int n,root,topt,nt[maxn],sx,sy;
long long ans;
struct da{int lc,rc;}a[4*maxn];
struct qu{int op;long long x,y;}q[maxn];
vector<int>now[4*maxn];
vector<int>tu[4*maxn];
bool cmp(int aa,int bb)
{
	if ((double)(q[aa].y-sy)*(q[bb].x-sx)==(double)(q[bb].y-sy)*(q[aa].x-sx)) return abs(q[aa].x-sx)<abs(q[bb].x-sx);
return (double)(q[aa].y-sy)*(q[bb].x-sx)<(double)(q[bb].y-sy)*(q[aa].x-sx);
}
void build_tree(int &n,int l,int r)
{
	n=++topt; if (l==r) return ;
	int mid=(l+r)>>1;
	build_tree(lch,l,mid); build_tree(rch,mid+1,r);
}
void tree_add(int n,int L,int R,int l,int r,int k)
{
	if (L==l && R==r) {now[n].pb(k); return ;}
	int mid=(L+R)>>1;
	if (r<=mid) tree_add(lch,L,mid,l,r,k);
	else if (l>=mid+1) tree_add(rch,mid+1,R,l,r,k);
	else tree_add(lch,L,mid,l,mid,k),tree_add(rch,mid+1,R,mid+1,r,k);
}
bool cro(int a,int b,int c)
{return (double)(q[c].y-q[b].y)*(q[b].x-q[a].x)<(double)(q[b].y-q[a].y)*(q[c].x-q[b].x);}
void work(int n,int l,int r)
{
	if (now[n].size()) 
	{
		sy=1e9+10;
		for (auto i:now[n]) 
         if (q[i].y<sy) {sx=q[i].x; sy=q[i].y;}
		sort(now[n].begin(),now[n].end(),cmp);
		int rr=-1;
		for (auto i:now[n])
		{
			while (rr>=1 && cro(tu[n][rr-1],tu[n][rr],i)) tu[n].er(),rr--;
			tu[n].pb(i); rr++;
		}
	}
	if (l==r) return;
	int mid=(l+r)>>1;
	work(lch,l,mid); work(rch,mid+1,r);
}
long long calc(int n,long long kk) {return 1ll*q[n].x*kk+1ll*q[n].y;}
void qury(int n,int l,int r,int lc,long long mul)
{
	if (tu[n].size())
	{
		int ll=0,rr=tu[n].size()-1;
		while (ll<=rr-20)
		{
			int lmid=ll+(rr-ll)/3;
			int rmid=rr-(rr-ll)/3;
			if (calc(tu[n][rmid],mul)>=calc(tu[n][lmid],mul)) 
			 {ll=lmid; ans=max(ans,calc(tu[n][rmid],mul));}
			else {rr=rmid; ans=max(ans,calc(tu[n][lmid],mul));} 
		}
		for (int i=ll;i<=rr;i++) ans=max(ans,calc(tu[n][i],mul));
	}
	if (l==r) return;
	int mid=(l+r)>>1;
	if (lc<=mid) qury(lch,l,mid,lc,mul);else qury(rch,mid+1,r,lc,mul);
}
int main()
{
	scanf("%d",&n); for (int i=1;i<=n;i++) nt[i]=n;
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&q[i].op);
		if (q[i].op==1) scanf("%lld%lld",&q[i].x,&q[i].y);
		else scanf("%lld",&q[i].x);
		if (q[i].op==2) nt[q[i].x]=i;
	}
	build_tree(root,1,n);
	for (int i=1;i<=n;i++)
	if (q[i].op==1) tree_add(root,1,n,i,nt[i],i);
	work(root,1,n);
	for (int i=1;i<=n;i++)
	if (q[i].op==3) 
	{
		ans=-inf; qury(root,1,n,i,q[i].x);
		if (ans==-inf) printf("EMPTY SET\n");else printf("%lld\n",ans);
	}
return 0;
}		
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
678f网址导航精美版(免费版) 源码简介: 1:整站全部生成html,易于搜索引擎收录 2:全后台化管理,操作简单 3:新站登陆功能 4:密码md5加密 5:后台登陆验证码识别 6:后台美化 7:新站登陆验证码识别 8:网站信息设置:网站名称,网站地址,站长邮箱等 9:无需修改任何网页,安装更为简单 10:网站信息后台设置 11:优化后台管理 12:网站推荐 13:模板后台管理 14:网站维护时可设置关闭“新站登陆”功能 15:可修改后台管理目录 16:分类目录、分类页文件名后台修改 17:网站安装目录调用标签 18:网址分类集合调用标签 19:服务器信息或组件查询 20:将网址分类从页面式修改为目录式,更适宜搜索引擎收录 21:所有删除增加2次确认,防止误操作 22:采用新的网站审核机制 23:类别合并功能 24:重复域名禁止登陆功能 25:“实用酷站”管理 演示:http://www.678f.com 下载:http://678f.5944vip.com/dzy/m.rar 安装方法: 1:将源码全部上传到网站空间,进入后台管理页面 2: 点击“网站信息管理”,修改网站信息 3:点击“生成html管理”,生成网站页面 4:后台管理登陆页:http://你的网址/admin/ 5:后台管理 帐号:admin 密码:www.678f.com 注:如果你是用本地IIS访问的话有可能将无法生成html建议上传到空间 部分文件和目录介绍: admin/ 后台管理目录,建议修改 本版主要改进了后台实用性 还有不明白的可以联系本版主 本版主 QQ 362657683 火星工作室
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值