sdoi2014-向量集-线段树-二分斜率

注意到线段树一个节点只有满了才会被用到,那时再建ConvexHull就行了。。。

#include <bits/stdc++.h>
using namespace std;
namespace my_useful_tools {
#define rep(_i, _k, _j) for(int _i = _k; _i <= _j; ++_i)
#define reu(_i, _k, _j) for(int _i = _k; _i <  _j; ++_i)
#define red(_i, _k, _j) for(int _i = _k; _j <= _i; --_i)
#define foreach(_i, _s) for(typeof(_s.begin()) _i = _s.begin(); _i != _s.end(); ++_i)
#define pb push_back
#define mp make_pair
#define ipir pair<int, int>
#define ivec vector<int>
#define clr(t) memset(t, 0, sizeof t)
#define pse(t, v) memset(t, v, sizeof t)
#define brl puts("")
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define file_hza freopen("input.txt", "r", stdin), freopen("output.txt", "w", stdout);
#define file_gen(x) freopen(#x".in", "w", stdout);
    const int INF = 0x3f3f3f3f;
    typedef long long LL;
    typedef double DB;
    inline void pc(char c) { putchar(c); }
    template<class T> inline T gcd(T a, T b) { return b == 0 ? a : gcd(b, a % b); }
    template<class T> inline void W(T p) { if(p < 0) pc(‘-‘), p = -p; if(p / 10 != 0) W(p / 10); pc(‘0‘ + p % 10); }
    template<class T> inline void Wn(T p) { W(p), brl; } template<class T> inline void W(T a, T b) { W(a), pc(‘ ‘), W(b); }
    template<class T> inline void Wn(T a, T b) { W(a), pc(‘ ‘), Wn(b); }
    template<class T> inline void W(T a, T b, T c) { W(a), pc(‘ ‘), W(b), pc(‘ ‘), W(c); }
    inline char gchar() { char ret = getchar(); for(; ret == ‘\n‘ || ret == ‘\r‘ || ret == ‘ ‘; ret = getchar()); return ret; }
    template<class T> inline void fr(T&ret) { char c = ‘ ‘; int flag = 1; for(c = getchar(); c != ‘-‘ && !(‘0‘ <= c && c <= ‘9‘); c = getchar());
        if(c == ‘-‘) flag = -1, ret = 0; else ret = c - ‘0‘; for(c = getchar(); ‘0‘ <= c && c <= ‘9‘; c = getchar()) ret = ret * 10 + c - ‘0‘;
        ret = ret * flag;
    }
    inline int fr() { int x; fr(x); return x; }
    template<class T> inline void fr(T&a, T&b) { fr(a), fr(b); } template<class T> inline void fr(T&a, T&b, T&c) { fr(a), fr(b), fr(c); }
    template<class T> inline T fast_pow(T base, T index, T mod = 2147483647, T ret = 1) {
        for(; index; index >>= 1, base = base * base % mod) if(index & 1) ret = ret * base % mod;
        return ret;
    }
};
using namespace my_useful_tools;

const int maxNode = 1e7;
const int maxQueryNode = 4e5 + 100;
const int maxSegNode = (maxQueryNode<<2);
struct Point {
    int x, y;
    Point() {}
    Point(int x, int y):x(x), y(y) {}
    bool operator < (const Point&rhs) const {
        return x < rhs.x || (x==rhs.x && y < rhs.y);
    }
    Point operator - (const Point&rhs) {
        return Point(x-rhs.x, y-rhs.y);
    }
} pool[maxNode], *loc = pool, P[maxQueryNode];
LL Dot(Point a, Point b) {
    return (LL)a.x*b.x+(LL)a.y*b.y;
}
LL Cross(Point a, Point b) {
    return (LL)a.x*b.y-(LL)a.y*b.x;
}

struct ConvexHull {
    Point *up, *dw;
    int un, dn;
    void buildConvexHull(Point*p, int sz) {
        sort(p, p+sz);
        up = loc;
        int cnt = -1;
        reu(i, 0, sz) {
            while (cnt > 0 && Cross(p[i]-up[cnt-1], up[cnt]-up[cnt-1]) <= 0)
                --cnt;
            ++cnt, up[cnt] = p[i];
        }
        loc += cnt+1;
        un = cnt+1;
        dw = loc;
        cnt = -1;
        reu(i, 0, sz) {
            while (cnt > 0 && Cross(p[i]-dw[cnt-1], dw[cnt]-dw[cnt-1]) >= 0)
                --cnt;
            ++cnt, dw[cnt] = p[i];
        }
        loc += cnt+1;
        dn = cnt+1;
    }
    LL qMaxDot(Point p) {
        LL ret = LLONG_MIN;
        int l = 0, r = un-1;
        while (l <= r) {
            if (r - l + 1 <= 2) {
                for (register int i = l; i <= r; ++i) {
                    ret = max(ret, Dot(up[i], p));
                }
                break;
            }
            int mid = (l+r)>>1;
            if (Dot(up[mid], p) < Dot(up[mid+1], p)) {
                l = mid+1;
            } else {
                r = mid;
            }
        }
        l = 0, r = dn-1;
        while (l <= r) {
            if (r - l + 1 <= 2) {
                for (register int i = l; i <= r; ++i) {
                    ret = max(ret, Dot(dw[i], p));
                }
                break;
            }
            int mid = (l+r)>>1;
            if (Dot(dw[mid], p) < Dot(dw[mid+1], p)) {
                l = mid+1;
            } else {
                r = mid;
            }
        }
    //    return ret;
    //    LL tmp = LLONG_MIN;
    //    for (int i = 0; i < un; ++i)
    //        tmp = max(tmp, Dot(up[i], p));
    //    for (int i = 0; i < dn; ++i)
    //        tmp = max(tmp, Dot(dw[i], p));
        return ret;
    }
} ch_pool[maxSegNode], *ch_loc = ch_pool;

struct SegNode {
    SegNode*lc, *rc;
    ConvexHull*ch;
    int l, r, sz;
    SegNode() {
        lc = rc = NULL;
        ch = ch_loc++;
        sz = 0;
    }
} sn_pool[maxSegNode], *sn_loc = sn_pool, *root;

void buildSegTree(int l, int r, SegNode*&rt) {
    if (rt == NULL) {
        rt = sn_loc++;
        rt->l = l, rt->r = r;
    }
    if (l == r) return ;
    int mid = (l+r)>>1;
    buildSegTree(l, mid, rt->lc), buildSegTree(mid+1, r, rt->rc);
}

void addPoint(int pos, SegNode*rt) {
    if (rt->l == rt->r) {
        ++rt->sz;
        if (rt->sz == rt->r-rt->l+1)
            rt->ch->buildConvexHull(P+(rt->l), rt->sz);
        return ;
    }
    int mid = (rt->l+rt->r)>>1;
    if (pos <= mid) addPoint(pos, rt->lc);
    else addPoint(pos, rt->rc);
    rt->sz = rt->lc->sz+rt->rc->sz;
    if (rt->sz == rt->r-rt->l+1)
        rt->ch->buildConvexHull(P+(rt->l), rt->sz);
}

Point qp;
LL Query(int ql, int qr, SegNode*rt) {
    if (ql <= rt->l && rt->r <= qr) {
        return rt->ch->qMaxDot(qp);
    }
    int mid = (rt->l+rt->r)>>1;
    LL ret = LLONG_MIN;
    if (ql <= mid) ret = max(ret, Query(ql, qr, rt->lc));
    if (mid < qr) ret = max(ret, Query(ql, qr, rt->rc));
    return ret;
}

int n;
bool e;
LL last_ans = 0LL;

inline int decode(int x) {
    if (e)
        return x ^ (last_ans & 0x7fffffff);
    else return x;
}

void print_tree(SegNode*rt) {
    if (rt == NULL) return ;
    printf("%d %d %d\n", rt->l, rt->r, rt->sz);
    print_tree(rt->lc);
    print_tree(rt->rc);
}

int main() {
    fr(n), e=(gchar()!=‘E‘);
    int x, y, ql, qr;
    int cnt = 0;
    buildSegTree(1, n, root);
    while (n--) {
        if (gchar() == ‘A‘) {
            x = decode(fr()), y = decode(fr());
            P[++cnt] = Point(x, y);
            addPoint(cnt, root);
        } else {
            x = decode(fr()), y = decode(fr());
            ql = decode(fr()), qr = decode(fr());
    //        printf("%d %d %d %d\n", x, y, ql, qr);
            qp = Point(x, y);
            last_ans = Query(ql, qr, root);
            printf("%lld\n", last_ans);
        }
    //    print_tree(root);
    }

    return 0;
}

时间: 2024-10-04 11:44:47

sdoi2014-向量集-线段树-二分斜率的相关文章

bzoj4311向量(线段树分治+斜率优化)

第二道线段树分治. 首先设当前向量是(x,y),剩余有两个不同的向量(u1,v1)(u2,v2),假设u1>u2,则移项可得,若(u1,v1)优于(u2,v2),则-x/y>(v1-v2)/(u1-u2),然后维护上凸壳后进行三分即可,复杂度O(nlog2n),如果将询问排序扫一遍,可以优化到O(nlogn),当然我没写. #include<bits/stdc++.h> #define lson l,mid,rt<<1 #define rson mid+1,r,rt&l

hdu 4893 (多校1007)Wow! Such Sequence!(线段树&amp;二分&amp;思维)

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 352    Accepted Submission(s): 104 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

UVA1455 - Kingdom(并查集 + 线段树)

UVA1455 - Kingdom(并查集 + 线段树) 题目链接 题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum (浮点数小数点一定是0.5) 查询y = fnum这条直线穿过了多少个州和city.州指的是连通的城市. 解题思路:用并查集记录城市之间是否连通,还有每一个州的y的上下界.建立坐标y的线段树,然后每次运行road操作的时候,对范围内的y坐标进行更新:更新须要分三种情况:两个州是相离,还是相交,还是包

hdu 5592 ZYB&#39;s Premutation (线段树+二分查找)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=5592 Problem Description ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutation,now he ask you to  restore the premutation.Pair (i,j)(i<j) is considered as a reverse

Educational Codeforces Round 64 (Rated for Div. 2) (线段树二分)

题目:http://codeforces.com/contest/1156/problem/E 题意:给你1-n  n个数,然后求有多少个区间[l,r] 满足    a[l]+a[r]=max([l,r]) 思路:首先我们去枚举区间肯定不现实,我们只能取把能用的区间去用,我们可以想下每个数当最大值的时候所做的贡献 我们既然要保证这个数为区间里的最大值,我们就要从两边扩展,找到左右边界能扩展在哪里,这里你直接去枚举肯定不行 这里我们使用了线段树二分去枚举左右区间最远能走到哪里,然后很暴力的去枚举短

BZOJ3533 [Sdoi2014]向量集 【线段树 + 凸包 + 三分】

题目链接 BZOJ3533 题解 我们设询问的向量为\((x_0,y_0)\),参与乘积的向量为\((x,y)\) 则有 \[ \begin{aligned} ans &= x_0x + y_0y \y &= -\frac{x_0}{y_0}x + \frac{ans}{y_0} \\end{aligned} \] 所以向量集里的向量实际上可以对应到平面上一组点,我们用一个斜率固定的直线去经过这些点,使得斜率最大或最小 当\(y_0 > 0\)时,要求截距最大 当\(y_0 <

[BZOJ2733] [HNOI2012]永无乡(并查集 + 线段树合并)

传送门 一看到第k大就肯定要想到什么权值线段树,主席树,平衡树之类的 然后就简单了 用并查集判断连通,每个节点建立一颗权值线段树,连通的时候直接合并即可 查询时再二分递归地查找 时间复杂度好像不是很稳定...但hzwer都用这种方法水过.. 正解好像是平衡树+启发式合并,以后学TT #include <cstdio> #include <iostream> #define N 100001 int n, m, q, cnt; int a[N], f[N], sum[N * 20],

YYHS-猜数字(并查集/线段树维护)

题目描述 LYK在玩猜数字游戏. 总共有n个互不相同的正整数,LYK每次猜一段区间的最小值.形如[li,ri]这段区间的数字的最小值一定等于xi. 我们总能构造出一种方案使得LYK满意.直到-- LYK自己猜的就是矛盾的! 例如LYK猜[1,3]的最小值是2,[1,4]的最小值是3,这显然就是矛盾的. 你需要告诉LYK,它第几次猜数字开始就已经矛盾了. 输入 第一行两个数n和T,表示有n个数字,LYK猜了T次.    接下来T行,每行三个数分别表示li,ri和xi. 输出 输出一个数表示第几次开

bzoj3533: [Sdoi2014]向量集

Description 维护一个向量集合,在线支持以下操作:"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)的点积的最大值.    集合初始时为空. Input 输入的第一行包含整数N和字符s,分别表示操作数和数据类别:    接下来N行,每行一个操作,格式如上