对应 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)
}
}
}
}
C:
#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;
}