线段树(区间更新)codeforces 292E Copying Data

对应 codeforces 题目:点击打开链接

E. Copying Data
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

We often have to copy large volumes of information. Such operation can take up many computer resources. Therefore, in this problem you are advised to come up with a way to copy some part of a number array into another one, quickly.

More formally, you've got two arrays of integers a1, a2, ..., an and b1, b2, ..., bn of length n. Also, you've got m queries of two types:

  1. Copy the subsegment of array a of length k, starting from position x, into array b, starting from position y, that is, executeby + q = ax + q for all integer q (0 ≤ q < k). The given operation is correct — both subsegments do not touch unexistent elements.
  2. Determine the value in position x of array b, that is, find value bx.

For each query of the second type print the result — the value of the corresponding element of array b.

Input

The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 105) — the number of elements in the arrays and the number of queries, correspondingly. The second line contains an array of integers a1, a2, ..., an (|ai| ≤ 109). The third line contains an array of integers b1, b2, ..., bn (|bi| ≤ 109).

Next m lines contain the descriptions of the queries. The i-th line first contains integer ti — the type of the i-th query (1 ≤ ti ≤ 2). Ifti = 1, then the i-th query means the copying operation. If ti = 2, then the i-th query means taking the value in array b. If ti = 1, then the query type is followed by three integers xi, yi, ki (1 ≤ xi, yi, ki ≤ n) — the parameters of the copying query. If ti = 2, then the query type is followed by integer xi (1 ≤ xi ≤ n) — the position in array b.

All numbers in the lines are separated with single spaces. It is guaranteed that all the queries are correct, that is, the copying borders fit into the borders of arrays a and b.

Output

For each second type query print the result on a single line.

Examples
input
5 10
1 2 0 -1 3
3 1 5 -2 0
2 5
1 3 3 3
2 5
2 4
2 1
1 2 1 4
2 1
2 4
1 4 2 1
2 2
output
0
3
-1
3
2
3
-1

题意:

        给两个数组 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;
}





你可能感兴趣的:(线段树(区间更新)codeforces 292E Copying Data)