【bzoj3533】[Sdoi2014]向量集 線段樹+STL-vector維護凸包

題目描述函數

維護一個向量集合,在線支持如下操做:
"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)的點積的最大值。
集合初始時爲空。加密

輸入spa

輸入的第一行包含整數N和字符s,分別表示操做數和數據類別;
接下來N行,每行一個操做,格式如上所述。
請注意s≠'E'時,輸入中的全部整數都通過了加密。你可使用如下程序獲得原始輸入:
inline int decode (int x long long lastans) {
     return x ^ (lastans & Ox7fffffff);
}
其中x爲程序讀入的數,lastans爲以前最後一次詢問的答案。在第一次詢問以前,lastans=0。
code

注:向量(x,y)和(z,w)的點積定義爲xz+yw。blog

輸出it

對每一個Q操做,輸出一個整數表示答案。io

樣例輸入ast

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
class

樣例輸出程序

13
17
17


題解

線段樹+STL-vector維護凸包

本質是什麼呢:給出 $x_0$ 和 $y_0$ ,求知足條件的 $x,y$ 使得 $x_0x+y_0y$ 最大。

咱們不妨設這個值是 $c$ ,則要最大化 $c$ 。

當 $y>0$ 時:

給這個式子 $c=x_0x+y_0y$ 變形,得:$y=-\frac {x_0}{y_0}x+\frac c{y_0}$ 。想要 $c$ 最大,即要 $\frac c{y_0}$ 最大。

至關因而一條斜率爲 $-\frac{x_0}{y_0}$ 的直線,要使縱截距最大,答案必定在上凸殼上,且所選點與答案造成單峯函數。

所以維護上凸殼,在凸殼上二分便可。

$y<0$ 的狀況同理,維護下凸殼並二分便可。$y=0$ 的狀況只要求 $x$ 最大/小,在兩個凸殼上二分均可以。

考慮使用線段樹維護一段區間的凸殼。

因爲強制在線,所以不能提早求凸殼。但咱們能夠發現:若是線段樹的一個節點沒有被所有加入(即沒加全),那麼這個點必定不會出如今詢問區間中。所以咱們在線段樹上插入,當且僅當 $tot==r$ 時,對該節點創建上凸殼便可。

時間複雜度 $O(n\log^2 n)$ 

#include <cstdio>
#include <vector>
#include <algorithm>
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
typedef long long ll;
struct point
{
	ll x , y;
	point() {}
	point(ll a , ll b) {x = a , y = b;}
	ll operator*(const point &a)const {return x * a.x + y * a.y;}
	ll operator^(const point &a)const {return x * a.y - y * a.x;}
	point operator-(const point &a)const {return point(x - a.x , y - a.y);}
	bool operator<(const point &a)const {return x == a.x ? y < a.y : x < a.x;}
};
vector<point> t[1600010] , v1[1600010] , v2[1600010];
char opt[5] , str[5];
void insert(int p , point o , int l , int r , int x)
{
	t[x].push_back(o);
	if(p == r)
	{
		sort(t[x].begin() , t[x].end());
		int i;
		for(i = 0 ; i <= r - l ; i ++ )
		{
			while(v1[x].size() > 1 && ((t[x][i] - v1[x][v1[x].size() - 1]) ^ (v1[x][v1[x].size() - 2] - v1[x][v1[x].size() - 1])) >= 0) v1[x].pop_back();
			v1[x].push_back(t[x][i]);
			while(v2[x].size() > 1 && ((t[x][i] - v2[x][v2[x].size() - 1]) ^ (v2[x][v2[x].size() - 2] - v2[x][v2[x].size() - 1])) <= 0) v2[x].pop_back();
			v2[x].push_back(t[x][i]);
		}
	}
	if(l == r) return;
	int mid = (l + r) >> 1;
	if(p <= mid) insert(p , o , lson);
	else insert(p , o , rson);
}
ll query1(int b , int e , point o , int l , int r , int x)
{
	if(b <= l && r <= e)
	{
		int L = 1 , R = v1[x].size() - 1 , Mid , Ans = 0;
		while(L <= R)
		{
			Mid = (L + R) >> 1;
			if(o * v1[x][Mid] > o * v1[x][Mid - 1]) Ans = Mid , L = Mid + 1;
			else R = Mid - 1;
		}
		return o * v1[x][Ans];
	}
	int mid = (l + r) >> 1;
	ll ans = -1ll << 62;
	if(b <= mid) ans = max(ans , query1(b , e , o , lson));
	if(e > mid) ans = max(ans , query1(b , e , o , rson));
	return ans;
}
ll query2(int b , int e , point o , int l , int r , int x)
{
	if(b <= l && r <= e)
	{
		int L = 1 , R = v2[x].size() - 1 , Mid , Ans = 0;
		while(L <= R)
		{
			Mid = (L + R) >> 1;
			if(o * v2[x][Mid] > o * v2[x][Mid - 1]) Ans = Mid , L = Mid + 1;
			else R = Mid - 1;
		}
		return o * v2[x][Ans];
	}
	int mid = (l + r) >> 1;
	ll ans = -1ll << 62;
	if(b <= mid) ans = max(ans , query2(b , e , o , lson));
	if(e > mid) ans = max(ans , query2(b , e , o , rson));
	return ans;
}
int main()
{
	int n , tot = 0 , i , l , r;
	ll last = 0;
	point o;
	scanf("%d%s" , &n , opt);
	for(i = 1 ; i <= n ; i ++ )
	{
		scanf("%s%lld%lld" , str , &o.x , &o.y) , o.x ^= last , o.y ^= last;
		if(str[0] == 'A') insert(++tot , o , 1 , n , 1);
		else
		{
			scanf("%d%d" , &l , &r) , l ^= last , r ^= last;
			if(o.y > 0) last = query1(l , r , o , 1 , n , 1);
			else last = query2(l , r , o , 1 , n , 1);
			printf("%lld\n" , last) , last &= 0x7fffffff;
			if(opt[0] == 'E') last = 0;
		}
	}
	return 0;
}
相關文章
相關標籤/搜索