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

链接: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|1

struct 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;
}
时间: 2024-08-25 04:41:29

ZOJ--3574--Under Attack II【线段树+欧拉公式】的相关文章

ZOJ 3574 Under Attack II 归并排序求逆序对

Under Attack II Time Limit: 5 Seconds      Memory Limit: 65536 KB Because of the sucessfully calculation in Under Attack I, Doctor is awarded with Courage Cross and promoted to lieutenant. But the war seems to end in never, now Doctor has a new order

zoj 3573 Under Attack(线段树 标记法 最大覆盖数)

Under Attack Time Limit:  10 Seconds      Memory Limit:  65536 KB Doctor serves at a military air force base. One day, the enemy launch a sudden attack and the base is under heavy fire. The fighters in the airport must take off to intercept enemy bom

FZU Problem 2171 防守阵地 II (线段树,区间更新)

 Problem 2171 防守阵地 II Accept: 143    Submit: 565Time Limit: 3000 mSec    Memory Limit : 32768 KB  Problem Description 部队中总共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,指挥部将选择M个士兵依次进入指定地点进行防守任务,获得的参考指数即为M个士兵的能力之和.随着时间的推移,指挥部将下达Q个指令来替换M个进行防守的士兵们,每个参加完防守

ZOJ 3772 Calculate the Function 线段树+矩阵

Calculate the FunctionTime Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Appoint description:  System Crawler  (2014-04-09) Description You are given a list of numbers A1A2 .. AN and M queries. For the i-th query

ZOJ 3633 Alice&#39;s present(线段树)

As a doll master, Alice owns a wide range of dolls, and each of them has a number tip on it's back, the tip can be treated as a positive integer. (the number can be repeated). One day, Alice hears that her best friend Marisa's birthday is coming , so

ZOJ 2671 Cryptography 矩阵乘法+线段树

B - Cryptography Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice ZOJ 2671 Description Young cryptoanalyst Georgie is planning to break the new cipher invented by his friend Andie. To do this, he must

FZU2171 防守阵地 II (线段树)

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2170 贴个baka爷的代码留念.. 数据出的有问题,输入的字符串长度不超过1000 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #incl

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 76[Submit][Status][Discuss] Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,

SPOJ 1557. Can you answer these queries II 线段树

Can you answer these queries II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://www.spoj.com/problems/GSS2/ Description Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse