ZOJ--3574--Under Attack II【线段树+欧拉公式】

来源:互联网 发布:手机淘宝掌柜热卖在哪 编辑:程序博客网 时间:2024/05/19 02:19

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3574

题意:一个坐标系,给出x1、x2限定左右边界,有n条直线,告诉每条直线的k和b,问在x1、x2区间内空间被直线分割成几部分


思路:

这道题是比赛时做的,AC之后发现别人都是用归并排序求逆序对数来解的。


说我的解法吧,首先拿到题的时候发现是划分区域这样的,第一下就想到了欧拉公式,但是n有30000,n^2找交点肯定要超时。土豪在纸上画了一下,一条直线必然在x1和x2处留下两点,如果一个直线左端点在另一个直线左端点上面,右端点在另一条线右端点下面,则他们必有一个交点。于是可以转换成线段树来做,给左端点从小到大排序,查询比当前直线右端点大的点的数目,更新欧拉公式要用到的点数和边数,注意交点在x1、x2时的情况。由于欧拉公式适用于连通图,所以要借助x1、x2两条边界线,但是直线没有端点,再虚拟出上下两个边界构出顶点,这样必定是连通图,所以初始时点数和边数都是4。

由于题目说了不会有三条线交于一点的情况,所以处理起来方便很多。


细节:

1.k*x1+b之后的数可能会很大,但是直线最多只有30000条,所以离散化处理。
2.我两个地方写逗了卡了较长时间。写下来防止以后犯逗:

(1)建树顺手写在了输入直线数之后,简单的样例发现不了,因为直线右端点如果没重合的话是不会有影响的。应当写在离散化之后。范围就到离散化后最大的数。

(2)调用query2函数是L、R的取值问题,我为了图省事R直接取到xx+1,如果前一组样例离散化后值较大,后一组较小,则xx+1就会取到上一组的情况,导致答案出错,我尝试建树时范围更大些,但是结果还是WA。解决方案是不要图省事,就取到xx。或者每组样例memset一下sum数组,但是这样显然很慢。


#include<cstring>#include<string>#include<sstream>#include<fstream>#include<iostream>#include<iomanip>#include<cstdio>#include<cctype>#include<algorithm>#include<queue>#include<deque>#include<map>#include<set>#include<vector>#include<stack>#include<ctime>#include<cstdlib>#include<functional>#include<cmath>using namespace std;#define PI acos(-1.0)#define MAXN 30010#define eps 1e-7#define INF 0x3F3F3F3F      //0x7FFFFFFF#define LLINF 0x7FFFFFFFFFFFFFFF#define seed 1313131#define MOD 1000000007#define ll long long#define ull unsigned ll#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1struct node{    int y1, y2;}line[MAXN];int sum[MAXN << 2];int n;map<int, int> mp;bool cmp(node x, node y){    return x.y1 < y.y1;}bool operator == (node p1, node p2){    return p1.y1 == p2.y1 && p1.y2 == p2.y2;}void pushup(int rt){    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];}void build(int l, int r, int rt){    sum[rt] = 0;    if(l == r)  return ;    int m = (l + r) >> 1;    build(lson);    build(rson);}void update(int pos, int l, int r, int rt){    if(l == r){        sum[rt]++;        return ;    }    int m = (l + r) >> 1;    if(pos <= m)    update(pos, lson);    else    update(pos, rson);    pushup(rt);}int query1(int pos, int l, int r, int rt){    if(l == r){        return sum[rt];    }    int m = (l + r) >> 1;    if(pos <= m)    query1(pos, lson);    else    query1(pos, rson);}int query2(int L, int R, int l, int r, int rt){    if(L <= l && r <= R){        return sum[rt];    }    int m = (l + r) >> 1;    int res = 0;    if(L <= m)  res += query2(L, R, lson);    if(R > m)   res += query2(L, R, rson);    return res;}int aaa[MAXN];int fuck[MAXN];int main(){    int x1, x2;    int i, j, k, b;    ll ppp, lll;    while(scanf("%d%d", &x1, &x2) != EOF){        mp.clear();        ppp = 4;        lll = 4;        scanf("%d", &n);        int m = 0;        int flag = 0;        for(i = 0; i < n; i++){            scanf("%d%d", &k, &b);            line[m].y1 = k * x1 + b;            line[m].y2 = k * x2 + b;            if(line[m].y1 != line[m].y2)    flag = 1;            aaa[m] = line[m].y2;            m++;        }        sort(aaa, aaa + m);        int xx = unique(aaa, aaa + m) - aaa;        if(x1 == x2 && flag == 0){            printf("%d\n", xx + 1);            continue;        }        for(i = 0; i < xx; i++){            mp[aaa[i]] = i + 1;        }        build(1, xx + 1, 1);        sort(line, line + m, cmp);        m = unique(line, line + m) - line;//        cout<<m<<endl;        ll ans = 0;        for(i = 0; i < m; i++){            j = i;            while(line[i + 1].y1 == line[i].y1 && i + 1 < m)    i++;            ppp++;            lll += i - j + 1;            lll++;            for(int ii = j; ii <= i; ii++){                int ttt = mp[line[ii].y2];                int temp = query1(ttt, 1, n, 1);                if(!temp){                    lll++;                    ppp++;                }                if(ttt + 1 <= xx){                    temp = query2(ttt + 1, xx, 1, n, 1);                    ppp += temp;                    lll += temp * 2;                }            }            for(int ii = j; ii <= i; ii++){                update(mp[line[ii].y2], 1, n, 1);            }        }//        cout<<ppp<<" "<<lll<<endl;        ans = 2 - ppp + lll - 1;        printf("%lld\n", ans);    }    return 0;}


0 0
原创粉丝点击