ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces - 1191F - Tokitsukaze and Strange Rectangle - 组合数学 - 线段树

2019-07-13 21:52:17  阅读:357  来源: 互联网

标签:200005 1191F int ll cntl Codeforces Tokitsukaze cntr query


https://codeforces.com/contest/1191/problem/F
看了一下题解的思路,感觉除了最后一段以外没什么启发。

首先离散化x加快速度,免得搞多一个log。其实y不需要离散化。
规定无穷大就是xn+1这个很好理解嘿嘿。(反正开多了5个不怕)

注意到其实从上往下一行一行扫过去,每次必须新增的元素才是新的集合,那很容易想到一个不重不漏的办法就是每次计算“以点p[i]为加进去的新点中的结束的集合”,那么假设一开始p[i]的左侧有cntl个点,那么显然有(cntl+1)条线在p[i]的左侧,而p[i]的右侧有cntr个点,也是(cntr+1)条线。

这个cntl显然就是query(1,p[i].x-1),而右侧则是query(p[i].x+1,p[i+1].x-1),因为不能包含同y的下一个点p[i+1],而其中,上面的点选法也会产生区别。

那么每层加入一个正无穷也就是xn+1就可以了。

溢出这种现在我不会错的了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int n;
struct Point {
    int x, y;
    bool operator<(const Point &p)const {
        return y == p.y ? x<p.x: y>p.y;
        //y从上到下,x从左到右
    }
} p[200005];

int x[200005];
int y[200005];

ll sum;

const int MAXM = 200000;
int st[(MAXM << 2) + 5];

inline void push_up(int o) {
    st[o] = st[o << 1] + st[o << 1 | 1];
}

void build(int o, int l, int r) {
    if(l == r) {
        st[o] = 0;
    } else {
        int m = (l + r) >> 1;
        build(o << 1, l, m);
        build(o << 1 | 1, m + 1, r);
        push_up(o);
    }
}

void update(int o, int l, int r, int x, int v) {
    if(l == r) {
        //不是加,是赋值,同x的点是没有差别的
        st[o] = v;
        return;
    } else {
        int m = (l + r) >> 1;
        if(x <= m)
            update(o << 1, l, m, x, v);
        else if(x >= m + 1)
            update(o << 1 | 1, m + 1, r, x, v);
        push_up(o);
    }
}

int query(int o, int l, int r, int a, int b) {
    if(b < a)
        return 0;
    else if(a <= l && r <= b) {
        return st[o];
    } else {
        int m = (l + r) >> 1;
        int ans = 0;
        if(a <= m)
            ans = query(o << 1, l, m, a, b);
        if(b >= m + 1)
            ans += query(o << 1 | 1, m + 1, r, a, b);
        return ans;
    }
}

int vx[200005], vxtop;

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out", "w", stdout);
#endif // Yinku
    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &p[i].x, &p[i].y);
            x[i] = p[i].x;
            y[i] = p[i].y;
        }
        sort(x + 1, x + 1 + n);
        int xn = unique(x + 1, x + 1 + n) - (x + 1);
        sort(y + 1, y + 1 + n);
        int yn = unique(y + 1, y + 1 + n) - (y + 1);
        for(int i = 1; i <= n; i++) {
            p[i].x = lower_bound(x + 1, x + 1 + xn, p[i].x) - x;
            p[i].y = lower_bound(y + 1, y + 1 + yn, p[i].y) - y;
            //从1开始分配新的坐标
            //printf("(%d,%d)\n", p[i].x, p[i].y);
        }
        sort(p + 1, p + 1 + n);
        //扫描线
        sum = 0;
        build(1, 1, xn + 1);
        int beg = 1, cur = 1;
        while(beg <= n) {
            vxtop = 0;
            while(p[cur].y == p[beg].y) {
                update(1, 1, xn + 1, p[cur].x, 1);
                vx[++vxtop] = p[cur].x;
                /*
                //点是不会重合的,那包含这个最左侧的点的都是全新集合
                int cntl = query(1, 1, xn, 1, p[cur].x - 1);
                //在这个点的左侧有cntl个x不同的点,那就有cntl+1个位置
                //sum += (cntl + 1); X
                //是以这个点为右侧边界的,所以右侧没得选 X
                */
                //该层y中是以这个x点为右侧边界,但是两个x点之间的上层y也是可选的
                cur++;
            }
            vx[++vxtop] = xn + 1;
            for(int i = 1; i <= vxtop - 1; i++) {
                //该层最右端的新点为vx[i]的数量
                int cntl = query(1, 1, xn + 1, 1, vx[i] - 1);
                int cntr = query(1, 1, xn + 1, vx[i] + 1, vx[i + 1] - 1);
                sum += 1ll * (cntl + 1) * (cntr + 1);
            }
            beg = cur;
        }
        printf("%lld\n", sum);
    }
}

偶尔用下树状数组。

标签:200005,1191F,int,ll,cntl,Codeforces,Tokitsukaze,cntr,query
来源: https://www.cnblogs.com/Yinku/p/11182211.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有