【bzoj1568】 JSOI2008—Blue Mary開公司

http://www.lydsy.com/JudgeOnline/problem.php?id=1568 (題目連接)php

題意

  在線維護若干條直線,詢問一些橫座標上的最高直線的縱座標。node

Solution

  超哥線段樹=  =。能夠說是標記可持久化的一個好的應用吧。ios

  線段樹上一個節點爲一個容器,能夠存放一條直線。考慮插入一條直線時,當找到要插入的區間節點時,若是這個節點的容器沒東西則將這條直線直接放在這個節點的容器中。不然和容器中的線段比較,保留較高部分較多的直線,將另外一條直線做爲新的插入直線往左兒子或者右兒子遞歸處理,最後到葉子節點直接比較便可。spa

  這樣一次插入,在線段樹上最多覆蓋滿$log$個區間,每一個區間遞歸下去$log$層。查詢時間複雜度爲一個$log$。時間複雜度爲$O(nlog^2n)$blog

細節

  記得各類eps。遞歸

代碼

// bzoj1568
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf (1ll<<60)
#define eps 1e-8
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;
	
const int lim=50000,maxn=100010;
int n;
char ch[100];

struct seg {
	double k,b;
	double ch(int x) {return k*x+b;}
}t;
struct node {int cov;seg mx;}tr[maxn<<2];

double X(seg a,seg b) {
	return fabs(a.k-b.k)<eps ? inf : (a.b-b.b)/(b.k-a.k);
}
void insert(int k,int l,int r,seg g) {
	int mid=(l+r)>>1;
	if (!tr[k].cov) tr[k].cov=1,tr[k].mx=g;
	else {
		seg a1=g,a2=tr[k].mx;double x=X(a1,a2);
		if (a1.ch(l)<a2.ch(l) || (fabs(a1.ch(l)-a2.ch(l))<eps && a1.k<a2.k)) swap(a1,a2);
		if (x<=l || x>=r) {tr[k].mx=a1;return;}
		if (x<=mid) tr[k].mx=a2,insert(k<<1,l,mid,a1);
		else tr[k].mx=a1,insert(k<<1|1,mid+1,r,a2);
	}
}
double query(int k,int l,int r,int x) {
	if (l==r) return tr[k].cov ? tr[k].mx.ch(x) : 0;
	int mid=(l+r)>>1;double t;
	if (x<=mid) t=query(k<<1,l,mid,x);
	else t=query(k<<1|1,mid+1,r,x);
	return tr[k].cov ? max(t,tr[k].mx.ch(x)) : t;
}

int main() {
	scanf("%d",&n);
	for (int x,i=1;i<=n;i++) {
		scanf("%s",ch);
		if (ch[0]=='P') scanf("%lf%lf",&t.b,&t.k),insert(1,0,lim,t);
		if (ch[0]=='Q') scanf("%d",&x),printf("%lld\n",(LL)query(1,0,lim,x-1)/100);
	}
	return 0;
}
相關文章
相關標籤/搜索