1 solutions

  • 0
    @ 2025-5-19 20:11:07

    注意一下本题当中提到的关键信息 : x1x23×105\sum|x_1-x_2|\le 3\times 10^5,这意味着我们可以将所有的直线变成至多 3×105n3\times 10^5-n 个整点来存储(因为不需要考虑线段两端的端点,所以每个线段的点数是 x1x21|x_1-x_2|-1 个)。由于 log1.25109<93\log_{1.25}10^9 < 93,所以复杂度的上限是 O(93nlogn)O(93n\log n),而且根本跑不满。

    然后我们利用两个 unordered_mapmap 来存储上面这些整点。每次传入起点坐标和方向之后,利用 upper_boundprev(lower_bound) 找到其对应打到的镜面(也就是 x,yx,y 两个方向的前驱和后继,需要注意处理空容器或前驱后继不存在等极端情况)。

    只要光线强度小于 11,或者剩余时间为 00 就要停机。此外,当前方向没有镜面,或者当前剩余时间泡不到镜面时,也要直接返回结果,此时结果需要单独计算,需要注意一下浮点数转整数时是否可能带来误差(例如 5.9999999995 向下类型转成 5 这样的情况)。

    此外,我们除了维护离散的点之外,还需要维护这些点对应的镜面编号是多少,在碰撞时还需要维护其打向镜面的坐标、方向、碰撞时间。这样才能完整维护上面的对应信息。

    // feature \sum |x_1 - x_2| <= 300000
    #include <stdio.h>
    #include <algorithm>
    #include <map>
    #include <unordered_map>
    const double eps = 1e-8;
    const int M = 100010;
    struct fastIO
    {
        static const int BUFF_SZ = 1 << 18;
        char inbuf[BUFF_SZ], outbuf[BUFF_SZ];
        fastIO()
        {
            setvbuf(stdin, inbuf, _IOFBF, BUFF_SZ);
            setvbuf(stdout, outbuf, _IOFBF, BUFF_SZ);
        }
    } IO;
    
    int m;
    int op, k;
    struct seg
    {
        std::pair<int, int> st, ed;
        bool type; // true : k = 1, false : k = -1
        double a;
    } segs[M];
    bool del[M];
    struct Query
    {
        int x, y, d, t;
        double I;
    } query;
    // X : x (y, seg_idx) Y : y (x, seg_idx)
    std::unordered_map<int, std::map<int, int>> X, Y;
    
    void add_point(int x, int y, int u) { X[x][y] = u, Y[y][x] = u; }
    void del_point(int x, int y) { X[x].erase(X[x].find(y)), Y[y].erase(Y[y].find(x)); }
    
    void add_segment(int u)
    {
        if (segs[u].type)
        {
            int x = std::min(segs[u].st.first, segs[u].ed.first) + 1;
            int y = std::min(segs[u].st.second, segs[u].ed.second) + 1;
            while (x < std::max(segs[u].st.first, segs[u].ed.first))
                add_point(x, y, u), ++x, ++y;
        }
        else
        {
            int x = std::min(segs[u].st.first, segs[u].ed.first) + 1;
            int y = std::max(segs[u].st.second, segs[u].ed.second) - 1;
            while (x < std::max(segs[u].st.first, segs[u].ed.first))
                add_point(x, y, u), ++x, --y;
        }
    }
    
    void del_segment(int u)
    {
        if (segs[u].type)
        {
            int x = std::min(segs[u].st.first, segs[u].ed.first) + 1;
            int y = std::min(segs[u].st.second, segs[u].ed.second) + 1;
            while (x < std::max(segs[u].st.first, segs[u].ed.first))
                del_point(x, y), ++x, ++y;
        }
        else
        {
            int x = std::min(segs[u].st.first, segs[u].ed.first) + 1;
            int y = std::max(segs[u].st.second, segs[u].ed.second) - 1;
            while (x < std::max(segs[u].st.first, segs[u].ed.first))
                del_point(x, y), ++x, --y;
        }
    }
    
    struct info
    {
        int seg_no;
        int meet_time;
        int nxt_dir;
        int meet_x, meet_y;
        info(int no = 0, int t = 0, int d = 0, int x = 0, int y = 0) 
            : seg_no(no), meet_time(t), nxt_dir(d), meet_x(x), meet_y(y) {}
    };
    std::map<int, int>::iterator it;
    info find_nxt(int x, int y, int dir)
    {
        if (dir == 0 || dir == 2)
        {
            if ((!Y.count(y)) || Y[y].empty())
                return info();
            if (dir == 0)
            {
                it = Y[y].upper_bound(x);
                if (it == Y[y].end())
                    return info();
                else
                {
                    int seg_no = it->second, meet_x = it->first, meet_y = y;
                    int nxt_dir = segs[seg_no].type ? 1 : 3;
                    int meet_time = meet_x - x;
                    return info(seg_no, meet_time, nxt_dir, meet_x, meet_y);
                }
            }
            else
            {
                it = Y[y].lower_bound(x);
                if (it == Y[y].begin())
                    return info();
                else
                {
                    --it;
                    int seg_no = it->second, meet_x = it->first, meet_y = y;
                    int nxt_dir = segs[seg_no].type ? 3 : 1;
                    int meet_time = x - meet_x;
                    return info(seg_no, meet_time, nxt_dir, meet_x, meet_y);
                }
            }
        }
        else
        {
            if ((!X.count(x)) || X[x].empty())
                return info();
            if (dir == 1)
            {
                it = X[x].upper_bound(y);
                if (it == X[x].end())
                    return info();
                else
                {
                    int seg_no = it->second, meet_y = it->first, meet_x = x;
                    int nxt_dir = segs[seg_no].type ? 0 : 2;
                    int meet_time = meet_y - y;
                    return info(seg_no, meet_time, nxt_dir, meet_x, meet_y);
                }
            }
            else
            {
                it = X[x].lower_bound(y);
                if (it == X[x].begin())
                    return info();
                else
                {
                    --it;
                    int seg_no = it->second, meet_y = it->first, meet_x = x;
                    int nxt_dir = segs[seg_no].type ? 2 : 0;
                    int meet_time = y - meet_y;
                    return info(seg_no, meet_time, nxt_dir, meet_x, meet_y);
                }
            }
        }
    }
    
    struct ans
    {
        int x, y;
        int I;
        ans(int _x = 0, int _y = 0, int i = 0) : x(_x), y(_y), I(i) {}
        void print() const { printf("%d %d %d\n", x, y, I); }
    };
    
    std::pair<int, int> striaght(int cur_x, int cur_y, int cur_dir, int cur_time)
    {
        if (cur_dir == 0)
            return std::make_pair(cur_x + cur_time, cur_y);
        else if (cur_dir == 1)
            return std::make_pair(cur_x, cur_y + cur_time);
        else if (cur_dir == 2)
            return std::make_pair(cur_x - cur_time, cur_y);
        else
            return std::make_pair(cur_x, cur_y - cur_time);
    }
    
    ans solve(const Query& q)
    {
        int cur_x = q.x, cur_y = q.y, cur_dir = q.d;
        double I = q.I;
        int remain = q.t;
        while (I >= (1.0 - eps) && remain > 0)
        {
            info nxt = find_nxt(cur_x, cur_y, cur_dir);
            if ((!nxt.seg_no) || (nxt.meet_time > remain))
            {
                std::pair<int, int> stat = striaght(cur_x, cur_y, cur_dir, remain);
                return ans(stat.first, stat.second, (int)(I + eps));
            }
            else
            {
                remain -= nxt.meet_time;
                I *= segs[nxt.seg_no].a;
                cur_x = nxt.meet_x, cur_y = nxt.meet_y, cur_dir = nxt.nxt_dir;
            }
        }
        if (I < (1.0 - eps))
            return ans();
        else
            return ans(cur_x, cur_y, (int)(I + eps));
    }
    
    int main()
    {
        scanf("%d", &m);
        for (int i = 1; i <= m; ++i)
        {
            scanf("%d", &op);
            if (op == 1)
            {
                scanf("%d%d%d%d%lf", &segs[i].st.first, &segs[i].st.second, &segs[i].ed.first, &segs[i].ed.second, &segs[i].a);
                segs[i].type = (segs[i].st.first < segs[i].ed.first) == (segs[i].st.second < segs[i].ed.second);
                add_segment(i);
            }
            else if (op == 2)
            {
                scanf("%d", &k);
                del[k] = 1;
                del_segment(k);
            }
            else
            {
                scanf("%d%d%d%lf%d", &query.x, &query.y, &query.d, &query.I, &query.t);
                solve(query).print();
            }
        }    
    }
    

    Information

    ID
    31
    Time
    2000ms
    Memory
    512MiB
    Difficulty
    3
    Tags
    # Submissions
    18
    Accepted
    2
    Uploaded By