CẤU TRÚC dữ LIỆU NÂNG CAO

28 585 3
CẤU TRÚC dữ LIỆU NÂNG CAO

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

CHUYÊN ĐỀ: CẤU TRÚC DỮ LIỆU NÂNG CAO Đặng Tuấn Thành Trường THPT Chuyên Nguyễn Tất Thành, tỉnh Yên Bái Interval Tree công cụ hữu dụng sử dụng nhiều toán dãy số, quy toán xử lí dãy số, đặc biệt toán có nhiều công việc cần xử lí nhiều truy vấn xen kẽ Phần lí thuyết Interval Tree trình bày rõ ràng nhiều tài liệu chuyên gia, đồng nghiệp dạy bồi dưỡng học sinh giỏi chia sẻ, nên mạn phép không đề cập Do lực có hạn nên không viết nghĩ tập mà có sử dụng Interval Tree để giải Vì thế, chuyên đề thực chất tập sưu tầm, biên tập thành tập tài liệu để phục vụ công tác giảng dạy bồi dưỡng HSG môn Tin học Ở đây, trích dẫn tập nguồn từ SPOJ, Codeforce nhiều nguồn khác Với tập đề cập đến ba vấn đề: • Tóm tắt đề rõ ràng • Thuật toán tốt • Code demo (nếu có) Khi áp dụng tài liệu vào giảng dạy, thường bỏ phần “code demo” để không “làm hỏng học sinh”, phát đề cho học sinh.Với tập, sau học sinh nghiên cứu đề xuất ý tưởng (hoặc code nộp mà chưa AC), dẫn dắt, đưa giải thuật toán để học sinh “ngấm” toán Dần dần học sinh nắm tư tưởng Interval Tree ứng dụng linh động vào toán khác Tôi xin trích dẫn tài liệu tham khảo để biên tập thành chuyên đề này: • • • • • http://laptrinh.ntu.edu.vn/Problem/List http://codeforces.com/problemset http://vn.spoj.com/problems/oi/ https://onlylove97.wordpress.com/category/it/ https://doraemonvodanh.wordpress.com/category/thuat-toan/segment-tree/bai- tap-interval-tree/ • Quyển: Một số vấn đề ý môn Tin học – Nhóm tác giả Đại học Vinh Ứng dụng Interval Tree để giải toán sau: Bài Phần tử thứ Khttp://vn.spoj.com/problems/YPKTH/ Cho dãy số A có N phần tử nguyên phân biệt Cho Q truy vấn, truy vấn có dạng: L R K Yêu cầu: truy vấn xuất phần tử lớn thứ K sau xếp phần tử A L, AL+1, …, AR theo thứ tự tăng dần Giới hạn: ≤ N, Q ≤ 105 |Ai| ≤ 109 với ≤ i ≤ N 1≤L≤R≤N ≤ K ≤ R-L+1 Input: - Dòng chứa số N - Dòng chứa N số A1, A2, …, AN - Dòng chứa số Q - Q dòng tiếp theo, dòng chứa số L, R, K Output: Q dòng, dòng chứa câu trả lời cho truy vấn theo thứ tự nhập vào Ví dụ: Input Output 2154368 4 122 374 462 Thời gian chạy: 551 1s-3s THUẬT TOÁN : Dùng Segment Tree với nút lưu lại dãy từ l->r sort Dùng vector cho nút để giảm nhớ: nút xuất logN lần cây, nhớ NlogN Có thể tạo O(NlogN), lần hợp hai nút lại ta trộn hai đoạn O(n+m) với n, m kích thước hai đoạn Với truy vấn ta làm sau: Xét giá trị (gọi res) có dãy cách chặt nhị phân, (nút thực chất sort dãy tăng dần nên chặt nhị phân nút 1), đếm xem đoạn l r có phần tử nhỏ nó, nhỏ k tức phải tìm số lớn tương tự Với lần truy vấn l r ta lại chặt nhị phân nút nằm đoạn l r để tìm phần tử lớn ≤ res đồng thời kiểm tra xem res có mặt đếm số lượng phần tử nhỏ res (Chú ý phần tử phân biệt) Điều kiện để res nghiệm cnt == k-1 (cnt số lượng số < res) tìm thấy res đoạn l r Code demo: http://ideone.com/GTScHq #include using namespace std; typedef long long ll; typedef int64_t ll; typedef pair ii; #define EL printf("\n") #define pb push_back #define mp make_pair #define X first #define Y second typedef vector data; const int N = 100100; int n, q, a[N], L, R, k, res, cnt, f; data t[4*N], nil; data combine(data u, data v) { data ans = nil; int i = 0, j = 0; while (i < u.size() and j < v.size()) { if (u[i] < v[j]) ans.pb(u[i++]); else ans.pb(v[j++]); } while (i < u.size()) ans.pb(u[i++]); void get(int node, int l, int r) { if (r < L or R < l) return ; if (L ≤ l and r ≤ R) { int i = 0, j = t[node].size()-1, pos = -1; while (i ≤ j) { int mid = (i+j)/2; if (t[node][mid] ≤ res) { pos = mid; i = mid+1; } else j = mid-1; } if (pos == -1) return ; if (t[node][pos] == res) f = true; cnt += pos + 1; if (t[node][pos] == res) cnt ; return ; } int mid = (l+r)/2; get(node*2,l,mid); get(node*2+1,mid+1,r); } while (j < v.size()) ans.pb(v[j++]); return ans; } void build(int k, int l, int r) { if (l == r) { t[k].pb(a[l]); return ; } int mid = (l+r)/2; build(k*2, l, mid); build(k*2+1, mid+1, r); t[k] = combine(t[k*2], t[k*2+1]); } int main() { //freopen("YPKTH.INP","r",stdin); //freopen("YPKTH.OUT","w",stdout); scanf("%d", &n); for (int i=1;i≤n;i++) scanf("%d", &a[i]); build(1,1,n); scanf("%d", &q); while (q ) { scanf("%d%d%d", &L,&R,&k); int l = 0, r = t[1].size()-1; while (l ≤ r) { int mid = (l+r)/2; res = t[1][mid]; cnt = 0; f = 0; get(1,1,n); if (cnt == k-1 and f) { printf("%d\n", res); break; } if (cnt < k) l = mid+1; else r = mid-1; } } return 0; } Bài 2.Đoạn có tổng lớn http://vn.spoj.com/problems/GSS/ Cho dãy số a[1], a[2], , a[n] (|a[i]| ≤ 15000, n ≤ 50000) Hàm q(x, y) = max { tổng(a[i]+a[i+1]+ +a[j]), x ≤ i ≤ j ≤y } Cho m câu hỏi dạng x, y (1 ≤ x ≤ y ≤ n), (m ≤ 50000) -> tính q(x, y) Input - Dòng đầu n - Dòng thứ hai dãy a - Dòng thứ m - m dòng dòng cặp số x, y Output Lần lượt ghi q(x, y) tương ứng Mỗi kết ghi dòng Example Input: -1 12 Output: Thời gian chạy: Thuật toán: Sử dụng Segment Tree Một nút lưu giá trị : sum : tổng đoạn pre : tổng lớn đoạn tiền tố suf : tổng lớn đoạn hậu tố ans : tổng lớn đoạn Công thức hợp hai nút sau : res.sum= l.sum+ r.sum; res.pre= max(l.pre, l.sum+ r.pre); res.suf= max(r.suf, r.sum+ l.suf); res.ans= max(l.ans, r.ans, l.suf+ r.pre); Code demo: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include data make_data (int x) { data res; res.sum = x; res.pre = res.suf = res.ans = x; return res; } void make_tree(int k, int l, int r) { if (l == r) { t[k] = make_data(a[l]); return ; } int mid = (l+r)/2; make_tree(k*2, l, mid); make_tree(k*2+1, mid+1, r); using namespace std; typedef long long ll; typedef int64_t ll; typedef double real; const int const int const ll const real base = 1000000007; oo = INT_MAX; ooo = LONG_LONG_MAX; pi = acos(-1.0); t[k] = combine(t[k*2], t[k*2+1]); } data query(int k, int l, int r, int L, int R) { if (l == L and r == R) return t[k]; int mid = (l+r)/2; if (R ≤ mid) return query(k*2, l, mid, L, R); #define openf {freopen("INP.INP","r",stdin);freopen("OU T.OUT","w",stdout);} #define closef {fclose(stdin);fclose(stdout);} #define readln scanf("\n") #define writeln printf("\n") if (L > mid) return query(k*2+1, mid+1, r, L, R); return combine ( query(k*2, l, mid, L, mid), query(k*2+1, mid+1, r, mid+1, R) ); // -/ / } struct data { int sum, pre, suf, ans; }; const int maxn = 100000, maxt = 4*maxn; int n, a[maxn], m, L, R; data t[maxt]; int main() { //openf; scanf("%d", &n); for (int i=1;i≤n;i++) scanf("%d", &a[i]); data combine (data l, data r) make_tree(1,1,n); { data res; scanf("%d", &m); res.sum = l.sum + r.sum; while (m ) { res.pre = max(l.pre, l.sum + r.pre); scanf("%d%d",&L,&R); res.suf = max(r.suf, r.sum + l.suf); printf("%d\n",query(1,1,n,L,R).ans); res.ans = max( max(l.ans, r.ans), l.suf + } r.pre); return res; //closef; } return 0; } Bài Diện tích hình chữ nhật - http://vn.spoj.com/problems/AREA/ Trên mặt phẳng toạ độ người ta vẽ N hình chữ nhật Hãy tính diện tích che phủ N hình chữ nhật này, biết N hình chữ nhật song song với trục Ox Oy Input Dòng : Số nguyên N ( ≤ N ≤ 10000 ) N dòng tiếp theo, dòng gồm số nguyên x1, y1, x2, y2 tương ứng toạ độ góc trái góc phải hình chữ nhật thứ i.( ≤ x1 ≤ x2 ≤ 30000, ≤ y1 ≤ y2 ≤ 30000 ) Output Gồm dòng ghi diện tích phủ N hình chữ nhật Example Input: 10 10 20 20 15 15 25 30 Output: 225 Thời gian chạy: Thuật toán: Sử dụng Segment Tree (IT) Chuyển liệu đề cho sang dãy tọa độ x, x có lưu lại y1 y2 tương ứng hàng giới hạn trên, đồng thời lưu lại type -1 hay tương ứng cạnh đóng hay mở Sau sort lại mảng theo x Mục đích cách xử lí khoảng từ xi -> xi+1 xét dãy sort ta tính phần diện tích bao phủ y1 y2 Lúc ta dùng Segment Tree, nút lưu lại cnt số lượng đoạn phủ len tổng chiều dài Code demo:http://ideone.com/tGGNUI #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long typedef int64_t typedef double ll; ll; real; // -// struct Node { int x, y1, y2, type; }; struct Tree { int len, cnt; }; // -// const int N = 30010; void update(int k, int l, int r, int L, int R, int type) { if (r < L or R < l) return ; if (L ≤ l and r ≤ R) { t[k].cnt += type; if (type == 1) // them hcn nen bao phu ca canh t[k].len = (r-l+1); // chang han l = 5, r = thi t[k].len = (5,6,7,8) else { // truong hop xoa thi phai lay thong tin tu node if (t[k].cnt == 0) t[k].len = t[k*2].len + t[k*2+1].len; } return ; } int mid = (l+r)/2; update(k*2,l,mid,L,R,type); update(k*2+1,mid+1,r,L,R,type); if (t[k].cnt == 0) t[k].len = t[k*2].len + t[k*2+1].len; } int main() { //freopen("INP.INP","r",stdin); //freopen("OUT.OUT","w",stdout); scanf("%d", &n); for (int i=1;i≤n;i++) { int x1, y1, x2, y2; scanf("%d%d%d%d", &x1,&y1,&x2,&y2); a[i].x = x1; int n, x0; // x0 la vi tri cuoi cung dang xet ll res; Node a[N]; Tree t[5*N]; // luu ve phuong dien dai, khong phai toa (*) // // a[i+n].x = x2; a[i].y1 = a[i+n].y1 = y1; a[i].y2 = a[i+n].y2 = y2; a[i].type = 1; a[i+n].type = -1; } n *= 2; sort(a+1,a+n+1,cmp); bool cmp(const Node u, const Node v) { //for (int i=1;i≤n;i++) return (u.x < v.x or (u.x == v.x and u.type // printf("%d %d %d %d\n", a[i].x, a[i].y1, < v.type)); a[i].y2, a[i].type); } for (int i=1;i≤n;i++) { //cout [...]... về chiều cao. Bác John đã chuẩn bị một danh sách gồm Q (1 ≤ Q ≤ 200000) đoạn các con bò và chiều cao của chúng (trong phạm vi [1, 1000000]) Với mỗi đoạn, bác John muốn xác định chênh lệch chiều cao giữa con bò thấp nhất và cao nhất Bạn hãy giúp bác John thực hiện công việc này Dữ liệu • Dòng đầu tiên chứa 2 số nguyên N và Q • Dòng thứ i trong số N dòng sau chứa 1 số nguyên duy nhất, là độ cao của con... 1 số nguyên, là chênh lệch chiều cao giữa con bò thấp nhất và cao nhất thuộc đoạn tương ứng Ví dụ Dữ liệu: 63 1 7 3 4 2 15 5 15 46 22 Kết qủa 6 3 0 Thuật toán: Đây là 1 bài toán xử lí trên dãy số và cần truy cập đến những đoạn A B bất kì trong dãy, vì vậyinterval tree là 1 trong những lựa chọn tốt Bài này chúng ta có 1 điều may mắn là không cầnphải cập nhật lại chiều cao của các con bò, vì vậy thông... không Hãy cho biết kết quả của m câu hỏi trên Dữ liệu nhập: – Dòng đầu tiên là hai số nguyên n, m cách nhau một khoảng trắng (1 ≤ n, m ≤ 105) 19 – Dòng thứ hai là dãy ngoặc ban đầu gồm n dấu ngoặc ‘(‘ hay ‘)’ – Trong m dòng tiếp theo, tại dòng thứ i là hai số p i và ri của câu hỏi thứ i tương ứng, hai số cách nhau một khoảng trắng (1 ≤ pi ≤ ri ≤ n) Dữ liệu xuất: – Gồm m dòng ứng với m câu hỏi, nếu... tự nào đó Lưu ý con búp bê i có thể đặt vào bên trong con búp bê j nếu (ai < aj) Dữ liệu vào: 21 Dòng đầu tiên có 2 số N, M lần lượt là số lượng con búp bê của yenthanh132 và kích thước giới hạn của N con búp bê đó N luôn là số chẵn Dòng thứ 2 chứa N số ai, là kích thước của N con búp bê từ trái sang phải (1 ≤ ai ≤ M) Dữ liệu ra: Xuất ra số K theo yêu cầu của bài Nếu không có kết quả (không có cách sắp... lời đúng bằng cách xử lý danh sách và trả về các kết quả đúng Dữ liệu: * Dòng 1: Hai số nguyên cách nhau bởi khoảng trắng: N và M * Dòng 2 M+1: Mỗi dòng chứa một thao tác với ba số nguyên cách nhau bởi khoảng trắng: thao tác, S_i, và E_i Kết quả: * Dòng 1 số truy vấn: Với mỗi truy vấn, in ra kết quả là một số nguyên trên một dòng Ví dụ: Dữ liệu: 45 012 024 123 024 114 Kết quả: 1 2 Thuật toán: 24 Ta có... may mắn là không cầnphải cập nhật lại chiều cao của các con bò, vì vậy thông tin trong cây interval tree là cố định và tasẽ tạo cây interval tree dựa trên mảng chiều cao của các con bò Mỗi đoạn thì ta cần in ra chênhlệch độ cao con bò cao nhất và con bò thấp nhất, vì vậy chúng ta cần tìm được giá trị lớn nhất vàgiá trị nhỏ nhất trong các phần tử từ A đến B Ta có thể dùng 1 cây interval tree với mỗi...+ Tạo thêm biến m lưu số điểm d2 lớn nhất vì theo như tài liệu d1 ta đã sort lại rồi thì không cần quan tâm điểm lớn hay nhỏ + Sau khi nhập dữ liệu thì sort lại dãy + Tạo biến q là vị trí đang duyệt trên dãy a ( từ 1 -> n, lần lượt xét các đoạn có cùng d1) Khi q > n thì xuất nghiệm ra, halt luôn trước... bảng - Ở mỗi lượt bắn, ktuan ghi lại tổng số ô mà các viên bi đã đi qua 25 Bạn hãy viết chương trình mô phỏng lại trò chơi và với mỗi lượt bắn, in ra tổng số ô mà các viên bi của lượt bắn đó đã đi qua Dữ liệu - Dòng đầu ghi 3 số N, K, Q - K dòng sau, mỗi dòng ghi một cặp số (u,v) thể hiện toạ độ (dòng, cột) của một vật cản - Q dòng sau, mỗi dòng ghi 4 giá trị c, D, u, v Ký tự c có thể là 'L', 'R', 'T',... được đưa vào ðây phải là một ô nằm trên biên của bảng ứng với ký tự c D là số lượng viên bi sẽ bắn ở lượt chơi này Kết quả Với mỗi lượt chơi, in ra tổng số ô mà các viên bi của lượt đó đã đi qua Ví dụ Dữ liệu 513 33 L231 T111 B555 Kết quả 3 2 25 Giải thích Viên bi đầu tiên của lượt 1 sẽ đi qua 2 ô (3,1) và (3,2) trước ghi gặp vật cản ở ô (3,3) Viên bi tiếp theo của lượt 1 sẽ đi qua ô (3,1) trước... học sinh sẽ chủ động hơn và sáng tạo cách giải quyết các bài tập gặp phải.Và đây là cách tôi cho học sinh tiếp cận về Interval Tree Do năng lực bản thân còn hạn chế nên việc biên tập tài liệu này từ nhiều nguồn tài liệu khác nhau không tránh khỏi những thiếu sót Tôi rất mong được nhận được sự ủng hộ và góp ý thẳng thắn của người đọc về chuyên đề này Tôi chân thành cảm ơn! Người viết chuyên đề Đặng Tuấn ... lệch chiều cao. Bác John chuẩn bị danh sách gồm Q (1 ≤ Q ≤ 200000) đoạn bò chiều cao chúng (trong phạm vi [1, 1000000]) Với đoạn, bác John muốn xác định chênh lệch chiều cao bò thấp cao Bạn giúp... đoạn bò từ A đến B Kết Gồm Q dòng, dòng chứa số nguyên, chênh lệch chiều cao bò thấp cao thuộc đoạn tương ứng Ví dụ Dữ liệu: 63 15 15 46 22 Kết qủa Thuật toán: Đây toán xử lí dãy số cần truy cập... không cầnphải cập nhật lại chiều cao bò, thông tin interval tree cố định tasẽ tạo interval tree dựa mảng chiều cao bò Mỗi đoạn ta cần in chênhlệch độ cao bò cao bò thấp nhất, cần tìm giá trị

Ngày đăng: 03/01/2016, 21:33

Mục lục

    Thuật toán: Sử dụng Segment Tree

    Một nút lưu các giá trị :

    Cho q câu hỏi, mỗi câu có dạng (u, v): Cho biết phần tử có giá trị lớn nhất thuộc đoạn [u, v]

    +) biến đổi có dạng: 0 x y value