Submission #1069027

# Submission time Handle Problem Language Result Execution time Memory
1069027 2024-08-21T14:38:20 Z Requiem Werewolf (IOI18_werewolf) C++17
100 / 100
965 ms 287668 KB
#include "werewolf.h"
#include<bits/stdc++.h>
//#define int long long
#define endl '\n'
#define fast ios_base::sync_with_stdio(NULL), cin.tie(NULL), cout.tie(NULL)
#define FOR(i, a, b) for(int i = a; i <= b; i++)
#define FORD(i, a, b) for(int i = a; i >= b; i--)
#define TASKNAME "werewolf"
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef pair<int, int> ii;
typedef pair<int, ii> iii;
 
/**
Cho đồ thị n đỉnh, m cạnh.
 
Ta có q truy vấn: Si Ei Li Ri.
Ta cần di chuyển từ Si dến Ei sao cho:
 
Ta có 2 trạng thái:
trạng thái 1: ta không được đi qua các đỉnh có chỉ số nhỏ hơn Li.
trạng thái 2: Ta không được đi qua các đỉnh có chỉ số lớn hơn Ri.
 
Ta bắt buộc phải chuyển trạng thái 1 lần trên đường đi tại các đỉnh từ Li đến Ri.
Ban đầu ta ở trạng thái 1.
 
subtask 1(7%): n <= 100, m <= 200, q <= 100
Từ Li ta sẽ dựng dược các tplt mà trạng thái 1 có thể di chuyển được.
Tử Ri ta sẽ dụng được các tplt mà trạng thái 2 có thể di chuyển được.
Từ Si ta sẽ tìm 1 đỉnh thuộc đoạn [Li, Ri] để chuyển trạng thái xong ta kiểm tra xem ta có thể di chuyển
từ đó đến Ei bằng cách bfs.
đpt: O(q * m * n)
subtask 2(8%): n <= 3000, m <= 6000, q <= 3000
 
Tối ưu từ subtask 1:
Thay vì phải tìm đường đi một cách thủ công thì ta có thể dùng ctdl dsu để trả lời nhanh hơn
 
subtask 3(31%): cây đường thẳng.
Đường đi của ta có dạng Si(0), v2(0) v3(0) ... vi(0) -> vi(1)... Ei(1)
Gọi VL là tập những đỉnh mà ta có thể đến được từ Si và đi qua những đỉnh lớn hơn Li.
Gọi VR là tập những đỉnh mà ta có thể đến được từ Ri và đi qua những đỉnh nhỏ hơn Ri.
Nếu như S = VL giao VR khác rỗng thì ta có thể đến được. (ta coi như là bfs 2 đầu)
 
Nhận xét của ta là VL và VR đều là những đoạn thẳng
Thì với 1 truy vấn, ta có thể sử dụng RMQ để giải và tìm VL và VR.
 
1 cách tiếp cận khác là dùng DSU?
Với truy vấn i, ta sẽ muốn biết (Si, Li) là vị trí xa nhất mà ta có thể đi được với các số đều không nhỏ hơn Li.
Tương tự ta cũng sẽ giải với truy vấn với (Ei, Ri). Thì ta sẽ có được cái đoạn đó. Từ đó ta sẽ tìm được giao điểm.
 
subtask 4(51%): điều kiện gốc.
Kế thừa ý tưởng từ subtask 3.
Dựng 2 cây reachbility Tree với trọng số cạnh là max của 2 đầu và min của 2 đầu.
 
Khi này ta sẽ tìm được các đoạn 2D mà Si và Ri quản lý. Kết hợp với các CTDL 2D thì ta có thể giải được cái giao điểm.
**/
 
const int MAXN = 6e6 + 9;
struct Question{
    int start, dest, l, r, id;
} query[MAXN];
 
int numNode, numEdge, numQuery;
ii edge[MAXN];
 
struct DisjointSetUnion{
    vector<int> lab;
    DisjointSetUnion(int _sz = 0){
        lab.resize(_sz + 9, -1);
        fill(lab.begin(), lab.end(), -1);
    }
 
    int root(int u){
        return ((lab[u] < 0) ? u : lab[u] = root(lab[u]));
    }
 
    bool unite(int u, int v){
        u = root(u);
        v = root(v);
        if (u != v){
            lab[u] += lab[v];
            lab[v] = u;
            return true;
        }
        return false;
    }
};
 
struct BinaryIndexedTree{
    vector<int> BIT;
    int _sz = 0;
    BinaryIndexedTree(int _n = 0){
        _sz = _n;
        BIT.resize(_sz + 9, 0);
    }
    int get(int id){
        int res = 0;
        for(int i = id; i > 0; i -= i & (-i)){
            res += BIT[i];
        }
        return res;
    }
 
    void upd(int id, int x){
        for(int i = id; i <= _sz; i += i & (-i)){
            BIT[i] += x;
        }
    }
};
struct XY2D{
 
 
    vector<ii> point; //cac diem can kiem tra.
    vector<pair<ii, ii>> rect;
    vector<pair<ii,ii>> eventPoint;
    vector<int> answer, mark;
 
    int numEventPoint = 0;
    vector<int> countPoint; //voi moi diem ta dem coi co bao nhieu diem ma co Xj <= Xi, Yj <= Yi.
 
    vector<int> listVal;
 
    int getVal(int x){
        return lower_bound(listVal.begin(), listVal.end(), x) - listVal.begin() + 1;
    }
 
    //rectangle chua 2 x1 < x2, y1 < y2.
    vector<int> countPointInRect(vector<pair<ii,ii>> &rectangle, vector<ii> &pts){
        point = pts;
        rect= rectangle;
        BinaryIndexedTree BIT(800000);
 
 
 
        FOR(i, 0, point.size() - 1){
            eventPoint.pb({point[i], {numEventPoint++, -1}});
        }
        mark.resize(rect.size());
        FOR(i, 0, rect.size() - 1){
            int x1 = rect[i].fi.fi;
            int y1 = rect[i].fi.se;
            int x2 = rect[i].se.fi;
            int y2 = rect[i].se.se;
            mark[i] = numEventPoint;
            eventPoint.pb({{x1 - 1, y1 - 1}, {numEventPoint++, i}});
            eventPoint.pb({{x2, y1 - 1}, {numEventPoint++, i}});
            eventPoint.pb({{x1 - 1, y2}, {numEventPoint++, i}});
            eventPoint.pb({{x2, y2},{numEventPoint++, i}});
        }
        sort(eventPoint.begin(), eventPoint.end(), [&](const pair<ii, ii> &a, const pair<ii, ii> &b){
            return ((a.fi.fi == b.fi.fi) ? ((a.fi.se == b.fi.se) ? a.se.se < b.se.se : a.fi.se < b.fi.se) : (a.fi.fi < b.fi.fi));
        });
 
        FOR(i, 0, numEventPoint - 1){
            listVal.pb(eventPoint[i].fi.fi);
            listVal.pb(eventPoint[i].fi.se);
        }
        countPoint.resize(numEventPoint);
 
        sort(listVal.begin(), listVal.end());
        listVal.erase(unique(listVal.begin(), listVal.end()), listVal.end());
        FOR(i, 0, numEventPoint - 1){
//            printf("PTS %lld %lld %lld %d\n", eventPoint[i].fi.fi, eventPoint[i].fi.se, eventPoint[i].se.fi, eventPoint[i].se.se);
            eventPoint[i].fi.fi = getVal(eventPoint[i].fi.fi);
            eventPoint[i].fi.se = getVal(eventPoint[i].fi.se);
        }
        for(int i = 0; i < eventPoint.size(); i++){
            if (eventPoint[i].se.se != -1){
                int id = eventPoint[i].se.fi;
                countPoint[id] += BIT.get(eventPoint[i].fi.se);
//                printf("Query %d\n", eventPoint[i].fi.se);
 
//                printf("%d\n", countPoint[id]);
            }
            if (eventPoint[i].se.se == -1) {
//                printf("UPD %d\n", eventPoint[i].fi.se);
                BIT.upd(eventPoint[i].fi.se, 1);
            }
        }
//        printf("\n");
 
        answer.resize(rect.size());
//        FOR(i, 0, numEventPoint - 1){
//            printf("%d \n", countPoint[i]);
//        }
        FOR(i, 0, rect.size() - 1){
            answer[i] = countPoint[mark[i] + 3] - countPoint[mark[i] + 1] - countPoint[mark[i] + 2] + countPoint[mark[i]];
        }
        return answer;
    }
};
namespace subtask1{
    bool check(){
        return numNode <= 3000 and numEdge <= 6000;
    }
    bool solve(int S, int E, int L, int R){
        DisjointSetUnion Left(numNode), Right(numNode);
        FOR(i, 0, numEdge - 1){
            if (edge[i].fi >= L and edge[i].se >= L) Left.unite(edge[i].fi, edge[i].se);
        }
 
        FOR(i, 0, numEdge - 1){
            if (edge[i].fi <= R and edge[i].se <= R) Right.unite(edge[i].fi, edge[i].se);
        }
 
        FOR(i, 0, numNode - 1){
            if (Left.root(i) == Left.root(S) and Right.root(i) == Right.root(E)) return true;
        }
        return false;
    }
}
 
struct reachabilityTree{
    vector<vector<int>> reachTree;
    vector<vector<int>> P;
    vector<ii> listEdge;
    vector<int> in, out, etour;
 
    void dfs(int u, int p){
        in[u] = etour.size();
        etour.pb(u);
        P[0][u] = p;
        for(auto v: reachTree[u]){
            if (v == p) continue;
            dfs(v, u);
        }
        out[u] = etour.size() - 1;
    }
 
    void init(){
        in.resize(numNode + numEdge);
        out.resize(numNode + numEdge);
        reachTree.resize(numNode + numEdge);
 
        P.resize(30, vector<int>(numNode + numEdge, -1));
    }
 
    int jumpLeft(int u, int lb){
        int res = 0;
        FORD(i, 20, 0){
            if (P[i][u] != -1 and min(listEdge[P[i][u] - numNode].fi, listEdge[P[i][u] - numNode].se) >= lb) {
                u = P[i][u];
            }
        }
        return u; //tim dinh xa nhat ve phia tren sao cho no la nhung dinh den duoc tu u thong qua nhung canh lon hon lb
    }
 
    int jumpRight(int u, int rb){
        int res = 0;
        FORD(i, 20, 0){
            if (P[i][u] != -1 and max(listEdge[P[i][u] - numNode].fi, listEdge[P[i][u] - numNode].se) <= rb) {
                u = P[i][u];
            }
        }
        return u; //tim dinh xa nhat ve phia tren sao cho no la nhung dinh den duoc tu u thong qua nhung canh nho hon rb.
    }
    void build(ii edge[]){
        DisjointSetUnion DSU(numNode + numEdge);
        init();
        FOR(i, 0, numEdge - 1){
            int u = edge[i].fi;
            int v = edge[i].se;
            listEdge.pb({u, v});
            int rt1 = DSU.root(u);
            int rt2 = DSU.root(v);
 
            if (DSU.unite(i + numNode, rt1)){
//                printf("RT: %lld %lld\n", i + numNode, rt1);
                reachTree[i + numNode].pb(rt1);
            }
 
            if (DSU.unite(i + numNode, rt2)){
//                printf("RT: %lld %lld\n", i + numNode, rt2);
                reachTree[i + numNode].pb(rt2);
            }
        }
 
        FORD(i, numEdge + numNode - 1, 0){
            if (!in[i]) dfs(i, -1);
        }
 
//        FOR(i, 0, etour.size() - 1){
//            printf("%lld ", etour[i]);
//        }
//        printf("\n");
        FOR(i, 1, 20){
            FOR(j, 0, numNode + numEdge - 1){
                if (P[i - 1][j] == -1) P[i][j] = -1;
                else P[i][j] = P[i - 1][P[i - 1][j]];
//                printf("%d ", P[i][j]);
            }
//            printf("\n");
        }
    }
} leftTree, rightTree;
namespace subtask2{
    bool check(){
        return true;
    }
 
    void solve(vector<int> &A){
        sort(edge, edge + numEdge, [&](const ii &a, const ii &b){
            return min(a.fi, a.se) > min(b.se, b.fi);
        });
//        FOR(i, 0, numEdge - 1){
//            printf("%lld %lld\n", edge[i].fi, edge[i].se);
//        }
        leftTree.build(edge);
        sort(edge, edge + numEdge, [&](const ii &a, const ii &b){
            return max(a.fi, a.se) < max(b.se, b.fi);
        });
//        FOR(i, 0, numEdge - 1){
//            printf("%lld %lld\n", edge[i].fi, edge[i].se);
//        }
        rightTree.build(edge);
        vector<pair<ii, ii>> listRect;
        vector<ii> listPoint;
 
        FOR(i, 0, numQuery - 1){
            int start = query[i].start;
            int dest = query[i].dest;
            int lb = query[i].l;
            int rb = query[i].r;
 
            int u = leftTree.jumpLeft(start, lb);
            int l1 = leftTree.in[u], r1 = leftTree.out[u];
//            printf("%d %d %d\n", u, l1, r1);
 
            int v = rightTree.jumpRight(dest, rb);
            int l2 = rightTree.in[v], r2 = rightTree.out[v];
//            printf("%d %d %d\n", v, l2, r2);
 
            listRect.pb({{l1, l2}, {r1, r2}});
        }
 
        FOR(i, 0, numNode - 1){
            listPoint.pb(ii(leftTree.in[i], rightTree.in[i]));
        }
 
        XY2D solution;
        vector<int> result = solution.countPointInRect(listRect, listPoint);
 
        for(int i = 0; i < result.size(); i++){
            A[i] = result[i] > 0;
        }
    }
}
std::vector<int> check_validity(int N, std::vector<int> X, std::vector<int> Y,
                                std::vector<int> S, std::vector<int> E,
                                std::vector<int> L, std::vector<int> R) {
  numNode = N;
  numEdge = X.size();
 
  numQuery = S.size();
 
  FOR(i, 0, numEdge - 1){
      edge[i] = ii(X[i], Y[i]);
  }
 
  FOR(i, 0, numQuery - 1){
      query[i] = {S[i], E[i], L[i], R[i], i};
  }
  std::vector<int> A(numQuery);
  if (subtask2::check()){
      subtask2::solve(A);
  }
  return A;
}

Compilation message

werewolf.cpp: In member function 'std::vector<int> XY2D::countPointInRect(std::vector<std::pair<std::pair<int, int>, std::pair<int, int> > >&, std::vector<std::pair<int, int> >&)':
werewolf.cpp:6:39: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
    6 | #define FOR(i, a, b) for(int i = a; i <= b; i++)
......
  137 |         FOR(i, 0, point.size() - 1){
      |             ~~~~~~~~~~~~~~~~~~~~~~     
werewolf.cpp:137:9: note: in expansion of macro 'FOR'
  137 |         FOR(i, 0, point.size() - 1){
      |         ^~~
werewolf.cpp:6:39: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<std::pair<int, int>, std::pair<int, int> > >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
    6 | #define FOR(i, a, b) for(int i = a; i <= b; i++)
......
  141 |         FOR(i, 0, rect.size() - 1){
      |             ~~~~~~~~~~~~~~~~~~~~~      
werewolf.cpp:141:9: note: in expansion of macro 'FOR'
  141 |         FOR(i, 0, rect.size() - 1){
      |         ^~~
werewolf.cpp:169:26: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<std::pair<int, int>, std::pair<int, int> > >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  169 |         for(int i = 0; i < eventPoint.size(); i++){
      |                        ~~^~~~~~~~~~~~~~~~~~~
werewolf.cpp:6:39: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<std::pair<int, int>, std::pair<int, int> > >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
    6 | #define FOR(i, a, b) for(int i = a; i <= b; i++)
......
  188 |         FOR(i, 0, rect.size() - 1){
      |             ~~~~~~~~~~~~~~~~~~~~~      
werewolf.cpp:188:9: note: in expansion of macro 'FOR'
  188 |         FOR(i, 0, rect.size() - 1){
      |         ^~~
werewolf.cpp: In member function 'int reachabilityTree::jumpLeft(int, int)':
werewolf.cpp:241:13: warning: unused variable 'res' [-Wunused-variable]
  241 |         int res = 0;
      |             ^~~
werewolf.cpp: In member function 'int reachabilityTree::jumpRight(int, int)':
werewolf.cpp:251:13: warning: unused variable 'res' [-Wunused-variable]
  251 |         int res = 0;
      |             ^~~
werewolf.cpp: In function 'void subtask2::solve(std::vector<int>&)':
werewolf.cpp:345:26: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  345 |         for(int i = 0; i < result.size(); i++){
      |                        ~~^~~~~~~~~~~~~~~
# Verdict Execution time Memory Grader output
1 Correct 4 ms 5724 KB Output is correct
2 Correct 3 ms 5724 KB Output is correct
3 Correct 2 ms 5724 KB Output is correct
4 Correct 2 ms 5556 KB Output is correct
5 Correct 2 ms 5724 KB Output is correct
6 Correct 2 ms 5724 KB Output is correct
7 Correct 2 ms 5724 KB Output is correct
8 Correct 4 ms 5720 KB Output is correct
9 Correct 2 ms 5724 KB Output is correct
# Verdict Execution time Memory Grader output
1 Correct 4 ms 5724 KB Output is correct
2 Correct 3 ms 5724 KB Output is correct
3 Correct 2 ms 5724 KB Output is correct
4 Correct 2 ms 5556 KB Output is correct
5 Correct 2 ms 5724 KB Output is correct
6 Correct 2 ms 5724 KB Output is correct
7 Correct 2 ms 5724 KB Output is correct
8 Correct 4 ms 5720 KB Output is correct
9 Correct 2 ms 5724 KB Output is correct
10 Correct 11 ms 8664 KB Output is correct
11 Correct 9 ms 8388 KB Output is correct
12 Correct 14 ms 8556 KB Output is correct
13 Correct 10 ms 8664 KB Output is correct
14 Correct 10 ms 8408 KB Output is correct
15 Correct 12 ms 9688 KB Output is correct
# Verdict Execution time Memory Grader output
1 Correct 717 ms 201928 KB Output is correct
2 Correct 821 ms 205304 KB Output is correct
3 Correct 721 ms 203004 KB Output is correct
4 Correct 673 ms 201976 KB Output is correct
5 Correct 675 ms 201920 KB Output is correct
6 Correct 776 ms 201980 KB Output is correct
7 Correct 622 ms 202144 KB Output is correct
8 Correct 744 ms 205340 KB Output is correct
9 Correct 594 ms 203004 KB Output is correct
10 Correct 530 ms 201928 KB Output is correct
11 Correct 556 ms 201912 KB Output is correct
12 Correct 539 ms 201932 KB Output is correct
13 Correct 789 ms 205052 KB Output is correct
14 Correct 804 ms 205008 KB Output is correct
15 Correct 827 ms 205292 KB Output is correct
16 Correct 786 ms 205560 KB Output is correct
17 Correct 599 ms 201976 KB Output is correct
# Verdict Execution time Memory Grader output
1 Correct 4 ms 5724 KB Output is correct
2 Correct 3 ms 5724 KB Output is correct
3 Correct 2 ms 5724 KB Output is correct
4 Correct 2 ms 5556 KB Output is correct
5 Correct 2 ms 5724 KB Output is correct
6 Correct 2 ms 5724 KB Output is correct
7 Correct 2 ms 5724 KB Output is correct
8 Correct 4 ms 5720 KB Output is correct
9 Correct 2 ms 5724 KB Output is correct
10 Correct 11 ms 8664 KB Output is correct
11 Correct 9 ms 8388 KB Output is correct
12 Correct 14 ms 8556 KB Output is correct
13 Correct 10 ms 8664 KB Output is correct
14 Correct 10 ms 8408 KB Output is correct
15 Correct 12 ms 9688 KB Output is correct
16 Correct 717 ms 201928 KB Output is correct
17 Correct 821 ms 205304 KB Output is correct
18 Correct 721 ms 203004 KB Output is correct
19 Correct 673 ms 201976 KB Output is correct
20 Correct 675 ms 201920 KB Output is correct
21 Correct 776 ms 201980 KB Output is correct
22 Correct 622 ms 202144 KB Output is correct
23 Correct 744 ms 205340 KB Output is correct
24 Correct 594 ms 203004 KB Output is correct
25 Correct 530 ms 201928 KB Output is correct
26 Correct 556 ms 201912 KB Output is correct
27 Correct 539 ms 201932 KB Output is correct
28 Correct 789 ms 205052 KB Output is correct
29 Correct 804 ms 205008 KB Output is correct
30 Correct 827 ms 205292 KB Output is correct
31 Correct 786 ms 205560 KB Output is correct
32 Correct 599 ms 201976 KB Output is correct
33 Correct 779 ms 202748 KB Output is correct
34 Correct 776 ms 228692 KB Output is correct
35 Correct 883 ms 213080 KB Output is correct
36 Correct 743 ms 204240 KB Output is correct
37 Correct 854 ms 209088 KB Output is correct
38 Correct 807 ms 207800 KB Output is correct
39 Correct 841 ms 208624 KB Output is correct
40 Correct 949 ms 287668 KB Output is correct
41 Correct 693 ms 205776 KB Output is correct
42 Correct 558 ms 204240 KB Output is correct
43 Correct 965 ms 251940 KB Output is correct
44 Correct 753 ms 208320 KB Output is correct
45 Correct 716 ms 212280 KB Output is correct
46 Correct 727 ms 208568 KB Output is correct
47 Correct 853 ms 206988 KB Output is correct
48 Correct 846 ms 205560 KB Output is correct
49 Correct 809 ms 207060 KB Output is correct
50 Correct 843 ms 205548 KB Output is correct
51 Correct 836 ms 287364 KB Output is correct
52 Correct 881 ms 287464 KB Output is correct