CF Croc Champ 2013 - Round 1 E. Copying Data
Codeforces Croc Champ 2013 - Round 1 E. Copying Data
数列a[i]とb[i]が与えられる。これらの数列について、以下の2種類のクエリを実行していくという問題。
・aのx番目からk個をbのy番目からk個にコピーする
・b[x]を出力する
以下前者をコピーのクエリと呼ぶ。
まず、b[u]を求めるときに、その位置の数が最後にいつ変更されたか(=その位置を含む最後のコピーのクエリはどれか)がわかれば、答えがわかりそうである。実際、そのコピーのクエリが何番目だったかがわかれば、そのクエリのx, yより、a[x + (u - y)]がb[u]に等しいことがわかる。なぜならば、そのコピーする部分の先頭がa[x]であり、u - yはその位置が先頭からどれくらい進んでいるかを表すので、a[x + u - y]がその位置にコピーされた数値に等しいのである。したがって、セグメントツリーなどをつくり、コピーのクエリがくるたびに、その区間をそのクエリが何番目であるかを上書きしていけばよい。
以下のサイトを参考にさせていただき、区間をある数で塗りつぶす実装をした。
Lazy Propagation Segment Tree
get関数はなんとなくで書いた。出力のクエリがくるごとに上記サイトのfixに相当するようなことをしている。
#include "bits/stdc++.h" using namespace std; #define OUT(x) cout << #x << " = " << x << endl; #define rep(i, n) for (int (i) = 0; (i) < (int)(n); (i)++) #define rer(i, l, r) for (int (i) = (int)(l); (i) <= (int)(r); (i)++) #define reu(i, l, r) for (int (i) = (int)(l); (i) < (int)(r); (i)++) #define each(i, v) for (auto i : v) #define all(x) (x).begin(), (x).end() #define rall(x) (x).rbegin(), (x).rend() #define pb push_back #define bp(x) __builtin_popcount(x) #define mp(x, y) make_pair((x), (y)) #define fi first #define se second #define setp(x) setprecision(x) #define mset(m, v) memset(m, v, sizeof(m)) #define sz(x) (int)(x.size()) static const int INF = 0x3f3f3f3f; static const long long INFL = 0x3f3f3f3f3f3f3f3fLL; static const int MOD = 1000000007; static const double PI = 3.141592653589793238462643383279; #define int long long typedef vector<double> vd; typedef vector<string> vs; typedef vector<bool> vb; typedef vector<int> vi; typedef pair<int, int> pii; typedef vector<pii> vpii; template<typename T> void pv(T a, T b) { for (T i = a; i != b; i ++) cout << *i << " "; cout << endl; } template<typename T, typename U> inline void amin(T &x, U y) { if (y < x) x = y; } template<typename T, typename U> inline void amax(T &x, U y) { if (x < y) x = y; } int in() { int _x; scanf("%d", &_x); return _x; } long long lin() {long long _x; scanf("%lld", &_x); return _x; }; struct SegmentTree { vector<int> lazy; int n; SegmentTree(int x) { n = pow(2, ceil(log2(x))); lazy.resize(2 * n - 1); for (int i = 0; i < 2 * n - 1; i ++) lazy[i] = INF;//初期化 } void push(int k) { if (lazy[k] == INF) return; lazy[k * 2 + 1] = lazy[k * 2 + 2] = lazy[k]; lazy[k] = INF; } int get(int k) { int res = INF; k += n - 1;//葉から根までを見ていき、INFじゃないものがあるたびにresを更新している。上にあるもののほうがあとで上書きされた値だからである if (lazy[k] != INF) res = lazy[k]; while (k > 0) { k = (k - 1) / 2; if (lazy[k] != INF) res = lazy[k]; } return res; } // [l, r)) void fill(int a, int b, int val) { fill(a, b, val, 0, 0, n); }//区間[a, b)をvalで塗りつぶす void fill(int a, int b, int val, int k, int l, int r) { if (r <= a || b <= l) return; if (a <= l && r <= b) { lazy[k] = val; return; } push(k); int m = (l + r) / 2; fill(a, b, val, k * 2 + 1, l, m); fill(a, b, val, k * 2 + 2, m, r); } }; struct Q { int x, y; }; signed main() { int n, q; cin >> n >> q; vi a(n), b(n); rep(i, n) cin >> a[i]; rep(i, n) cin >> b[i]; SegmentTree st(n); vector<Q> query; rep(i, q) { int t; cin >> t; if (t == 1) { int x, y, k; cin >> x >> y >> k; x --, y --; query.pb({x, y}); st.fill(y, y + k, query.size() - 1); //yからk個をquery.size() - 1(=クエリ番号)で塗りつぶす } else { int u; cin >> u; u --; if (st.get(u) == INF) cout << b[u] << endl; //そのままなら、一回もその位置にはコピーされていない else { int q = st.get(u); //クエリ番号を取り出してクエリを復元 int qx = query[q].x; int qy = query[q].y; cout << a[qx + u - qy] << endl; } } } return 0; }