본문 바로가기

Problem Solving/문제풀이

[BOJ] 15977 조화로운 행렬

2018 KOI 고등부 3번이다. 정해는 2d segment tree래서 그렇게 짰는데 사실 set+이분탐색이 훨씬 짧고 깔끔하고 빠르고 메모리 사용량도 적다고 한다. 하여튼 "정해"는 첫째 열 기준으로 정렬한 다음 둘째 열과 셋째 열에서 2d segment tree를 이용해서 pair의 LIS를 구해주면 된다. 메모리 사용량이 문제고 $200000 * (lg200000)^2$ 개만큼 노드 잡았더니 MLE 뜨길래 적당히 줄여서 해봤더니 맞았다. 왜 맞는지 진짜 모르겠는데 실제로 돌리면 같은 노드도 여러번 탐색하고 그래서 최악의 경우에도 노드 개수가 많이 넘어가지는 않는다고 한다. 시간은 5초 제한에 낭낭하게 3.7초 나왔다. (...) 시간복잡도는 $O(n lg n^2)$, 공간복잡도도 마찬가지.

다시는 2d segment tree를 짤 일이 없었으면 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include <bits/stdc++.h>
 
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> pii;
 
int m;
 
typedef struct node
{
    int val;
    int left, right;
    node() : val(0),left(-1),right(-1) {}
}Node;
Node N[55000000];
 
int ncnt=0;
int alloc() {return ncnt++;}
 
typedef struct SegmentTree
{
    int n,left,right;
    SegmentTree() : n(0), left(-1), right(-1) {}
    void initN(int _n) {n=_n+1;}
    int root=alloc();
 
    void update(int nidx, int st, int en, int idx, int diff)
    {
        Node& nd=N[nidx];
        if(idx<st || en<idx) return;
        if(st==en && st==idx)
        {
            nd.val=diff;
            return;
        }
        int mid=(st+en)>>1;
        int ma=0;
        if(idx<=mid)
        {
            if(nd.left==-1) nd.left=alloc();
            update(nd.left,st,mid,idx,diff);
            ma=max(ma,N[nd.left].val);
            if(nd.right!=-1) ma=max(ma,N[nd.right].val);
        }
        else
        {
            if(nd.right==-1) nd.right=alloc();
            update(nd.right,mid+1,en,idx,diff);
            ma=max(ma,N[nd.right].val);
            if(nd.left!=-1) ma=max(ma,N[nd.left].val);
        }
        nd.val=ma;
    }
    void update(int idx, int diff) {update(root,0,n-1,idx,diff);}
 
    int query(int nidx, int st, int en, int le, int ri)
    {
        Node& nd=N[nidx];
        if(en<le || ri<st) return 0;
        if(le<=st && en<=ri) return nd.val;
        int mid=(st+en)>>1;
        int ma=0;
        if(nd.left!=-1) ma=max(ma,query(nd.left,st,mid,le,ri));
        if(nd.right!=-1) ma=max(ma,query(nd.right,mid+1,en,le,ri));
        return ma;
    }
    int query(int le, int ri) {return query(root,0,n-1,le,ri);}
}ST;
ST STN[4000000];
 
int stn=0;
int allocST() {STN[stn].initN(m); return stn++;}
 
typedef struct Seg2D
{
    int n,root=allocST();
    Seg2D(int _n) : n(_n+1) {}
 
    void update(int nidx, int st, int en, int x, int y, int diff)
    {
        ST& nd=STN[nidx];
        if(x<st || en<x) return;
        if(st==en && st==x)
        {
            nd.update(y,diff);
            return;
        }
        int mid=(st+en)>>1;
        int ma=0;
        if(x<=mid)
        {
            if(nd.left==-1) nd.left=allocST();
            update(nd.left,st,mid,x,y,diff);
            ma=max(ma,STN[nd.left].query(y,y));
            if(nd.right!=-1) ma=max(ma,STN[nd.right].query(y,y));
        }
        else
        {
            if(nd.right==-1) nd.right=allocST();
            update(nd.right,mid+1,en,x,y,diff);
            ma=max(ma,STN[nd.right].query(y,y));
            if(nd.left!=-1) ma=max(ma,STN[nd.left].query(y,y));
        }
        nd.update(y,ma);
    }
    void update(int x, int y, int diff){update(root,0,n-1,x,y,diff);}
 
    int query(int nidx, int st, int en, int x1, int x2, int y1, int y2)
    {
        ST& nd=STN[nidx];
        if(x2<st || en<x1) return 0;
        else if(x1<=st && en<=x2) return nd.query(y1,y2);
        int mid=(st+en)>>1;
        int ma=0;
        if(nd.left!=-1) ma=max(ma,query(nd.left,st,mid,x1,x2,y1,y2));
        if(nd.right!=-1) ma=max(ma,query(nd.right,mid+1,en,x1,x2,y1,y2));
        return ma;
    }
    int query(int x1, int x2, int y1, int y2) {return query(root,0,n-1,x1,x2,y1,y2);}
}ST2;
 
typedef struct vecarr
{
   int x,y,z;
   //vecarr(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
}va;
 
bool comp_x(va a, va b) {return a.x<b.x;}
bool comp_y(va a, va b) {return a.y<b.y;}
bool comp_z(va a, va b) {return a.z<b.z;}
 
int main()
{
    int n;
    scanf("%d %d",&n,&m);
 
    if(n==2)
    {
        vector<pii> pv(m); vi dp;
        for(int i=0;i<m;i++scanf("%d",&pv[i].first);
        for(int i=0;i<m;i++scanf("%d",&pv[i].second);
        sort(pv.begin(),pv.end());
        for(int i=0;i<m;i++)
        {
            auto it=lower_bound(dp.begin(),dp.end(),pv[i].second);
            if(it==dp.end()) dp.push_back(pv[i].second);
            else *it=pv[i].second;
        }
        printf("%d",dp.size());
        return 0;
    }
 
    vector<va> V(m);
    for(int i=0;i<m;i++scanf("%d",&V[i].x);
    for(int i=0;i<m;i++scanf("%d",&V[i].y);
    for(int i=0;i<m;i++scanf("%d",&V[i].z);
    sort(V.begin(),V.end(),comp_y);
    for(int i=1;i<=V.size();i++) V[i-1].y=i;
    sort(V.begin(),V.end(),comp_z);
    for(int i=1;i<=V.size();i++) V[i-1].z=i;
    sort(V.begin(),V.end(),comp_x);
 
    int ma=0; ST2 S(m);
    for(int i=0;i<V.size();i++)
    {
        va& h=V[i];
        int val=S.query(0,h.y-1,0,h.z-1)+1;
        ma=max(ma,val);
        S.update(h.y,h.z,val);
    }
    printf("%d",ma);
    return 0;
}
 
cs




'Problem Solving > 문제풀이' 카테고리의 다른 글

[BOJ] 10067 수열 나누기  (0) 2018.10.29
[BOJ] 1693 트리 색칠하기  (0) 2018.10.22
[BOJ] 11377 열혈강호 3  (0) 2018.09.21
[BOJ] 7579 앱  (0) 2018.09.18
[BOJ] 2629 양팔저울  (0) 2018.09.06