对应 codeforces 题目:点击打开链接
给两个数组 a[] 和 b[],有两个操作,(1, x, y, k) 表示把数组 a[] 从下标 x 的那个数开始的 k 个数覆盖数组 b[] 的从下标 y 开始的 k 个数(即用 a[x]~a[x+k-1] 覆盖 b[y]~b[y+k-1]),(2, x) 表示请求输出数组 b[x] 的值。题目保证给出的数据合理。
思路:
线段树区间更新,线段树的每个结点维护数组 a[] 覆盖数组 b[] 的左右边界
试着用 Go 写了下,超时了~ 出乎意料,完全一样的方法。。。
Go :2000ms+
C :280ms
有点失望。。。
Go:
package main import "fmt" const N = 100010 var a [N]int type tree struct{ val, al, ar int mid, l, r int } var T [N]tree func down(rt int){ tal := T[rt].al tar := T[rt].ar lson_len := T[rt].mid - T[rt].l + 1 if tal != tar { T[rt<<1].al = tal T[rt<<1].ar = tal + lson_len - 1 T[rt<<1|1].al = tal + lson_len T[rt<<1|1].ar = tar T[rt].al = -1 T[rt].ar = -1 } } func build_tree(rt, l, r, pos int){ T[rt].al = -1 T[rt].ar = -1 T[rt].mid = (l + r) / 2 T[rt].l = l T[rt].r = r if l == r{ fmt.Scan(&T[rt].val) return } m := T[rt].mid if pos <= m { build_tree(rt<<1, l, m, pos) }else{ build_tree(rt<<1|1, m+1, r, pos) } } func update(rt, l1, r1, l2, r2 int){ l := T[rt].l r := T[rt].r if l2 == l && r2 == r{ T[rt].al = l1 T[rt].ar = r1 return } down(rt) m := T[rt].mid if r2 <= m{ update(rt<<1, l1, r1, l2, r2) }else if l2 > m{ update(rt<<1|1, l1, r1, l2, r2) }else{ update(rt<<1, l1, l1+(m-l2), l2, m) update(rt<<1|1, l1+(m-l2)+1, r1, m+1, r2) } } func query(rt, pos int) int{ l := T[rt].l r := T[rt].r if l == r{ if T[rt].al != -1{ return a[T[rt].al] }else{ return T[rt].val } } down(rt) m := T[rt].mid if pos <= m{ return query(rt<<1, pos) }else{ return query(rt<<1|1, pos) } } func main(){ var n, q int var od int var ax, bx, k int var x int for{ num, _ := fmt.Scanln(&n, &q) if num != 2{ break } var i int for i = 0; i < n; i++{ fmt.Scan(&a[i]) } for i = 0; i < n; i++{ build_tree(1, 0, n-1, i) } for i = 0; i < q; i++{ fmt.Scan(&od) if od == 1{ fmt.Scan(&ax, &bx, &k) ax-- bx-- update(1, ax, ax+k-1, bx, bx+k-1) }else if od == 2{ fmt.Scan(&x) x-- v := query(1, x) fmt.Println(v) } } } }
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 100010 int a[N]; int b[N<<2]; int al[N<<2]; int ar[N<<2]; void down(int rt, int lson_len) { if(al[rt] != ar[rt]){ al[rt<<1] = al[rt]; ar[rt<<1] = al[rt] + lson_len - 1; al[rt<<1|1] = al[rt] + lson_len; ar[rt<<1|1] = ar[rt]; al[rt] = ar[rt] = -1; } } void build_tree(int rt, int l, int r, int pos) { int mid; al[rt] = ar[rt] = -1; if(l == r){ scanf("%d", b + rt); return; } mid = (l + r) / 2; if(pos <= mid) build_tree(rt<<1, l, mid, pos); else build_tree(rt<<1|1, mid + 1, r, pos); } void update(int rt, int l, int r, int l1, int r1, int l2, int r2) { int mid; if(l2 == l && r2 == r){ al[rt] = l1; ar[rt] = r1; return; } mid = (l + r) / 2; down(rt, mid-l+1); if(r2 <= mid) update(rt<<1, l, mid, l1, r1, l2, r2); else if(l2 > mid) update(rt<<1|1, mid + 1, r, l1, r1, l2, r2); else{ update(rt<<1, l, mid, l1, l1+(mid-l2), l2, mid); update(rt<<1|1, mid+1, r, l1+(mid-l2)+1, r1, mid+1, r2); } } int query(int rt, int l, int r, int pos) { int mid; if(l == r){ if(al[rt] != -1) return a[al[rt]]; else return b[rt]; } mid = (l + r) / 2; down(rt, mid-l+1); if(pos <= mid) return query(rt<<1, l, mid, pos); else return query(rt<<1|1, mid + 1, r, pos); } int main() { #if 0 freopen("in.txt","r",stdin); #endif int n, q; while(~scanf("%d%d", &n ,&q)){ int i; for(i = 0; i < n; i++) scanf("%d", a + i); for(i = 0; i < n; i++){ build_tree(1, 0, n-1, i); } while(q--){ int od; scanf("%d", &od); if(od == 1){ int ax, bx, k; scanf("%d%d%d", &ax, &bx, &k); ax--; bx--; update(1, 0, n-1, ax, ax+k-1, bx, bx+k-1); } else if(od == 2){ int x; scanf("%d", &x); x--; printf("%d\n", query(1, 0, n-1, x)); } } } return 0; }