藍橋杯 演算法訓練 操作格子 (線段樹)

一葉之修發表於2019-03-10

 藍橋杯歷年真題題目及題解目錄彙總

 

 演算法訓練 操作格子  

時間限制:1.0s   記憶體限制:256.0MB

      

問題描述

有n個格子,從左到右放成一排,編號為1-n。

共有m次操作,有3種操作型別:

1.修改一個格子的權值,

2.求連續一段格子權值和,

3.求連續一段格子的最大值。

對於每個2、3操作輸出你所求出的結果。

輸入格式

第一行2個整數n,m。

接下來一行n個整數表示n個格子的初始權值。

接下來m行,每行3個整數p,x,y,p表示操作型別,p=1時表示修改格子x的權值為y,p=2時表示求區間[x,y]內格子權值和,p=3時表示求區間[x,y]內格子最大的權值。

輸出格式

有若干行,行數等於p=2或3的操作總數。

每行1個整數,對應了每個p=2或3操作的結果。

樣例輸入

4 3
1 2 3 4
2 1 3
1 4 3
3 1 4

樣例輸出

6
3

資料規模與約定

對於20%的資料n <= 100,m <= 200。

對於50%的資料n <= 5000,m <= 5000。

對於100%的資料1 <= n <= 100000,m <= 100000,0 <= 格子權值 <= 10000。

 

學到的東西是初始化線段樹資料的時候直接插入會比較好,而不是在建樹的時候push_up初始化,但是實際沒多大區別,這題官網沒給java好的資料,c++才能過,網上大多數的題解也是提交超時的,呵呵!

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm> 
#include<vector> 
#include<cmath>  
#include<sstream>
#include<cstdlib>
#include<queue>
using namespace std;
const int N = 400005;
int MAX(int a,int b){
	return a>b?a:b;
}
struct node{
	int l,r,sum,max;
}a[N];
void build(int n,int l,int r){
	a[n].l = l;
	a[n].r = r;
	a[n].max = 0;
	a[n].sum = 0;
	if(l == r) return;
	build(n*2,l,(l+r)/2);
	build(n*2+1,(l+r)/2+1,r);
}
void insert(int n,int pos,int num){
	a[n].sum += num; //更新加和 
	if(a[n].max < num) a[n].max = num;//更新最大值
	if(a[n].l == a[n].r) return;
	int mid = (a[n].l+a[n].r)/2;
	if(pos <= mid) insert(n*2,pos,num);
	else insert(n*2+1,pos,num); 
}
void change(int n,int pos,int num){
	if(pos == a[n].l && pos == a[n].r){//找到位置 
		a[n].max = num;
		a[n].sum = num;
		return;
	}
	int mid = (a[n].l + a[n].r )/2;
	if(pos <= mid) change(n*2,pos,num);
	else change(n*2+1,pos,num);
	a[n].sum = a[n*2].sum + a[n*2+1].sum;
	a[n].max = MAX(a[n*2].max,a[n*2+1].max);
}
int qsum(int n,int l,int r){
	if(l == a[n].l && r == a[n].r){//範圍相同,直接返回 
		return a[n].sum;
	}
	int mid = (a[n].l+a[n].r)/2;
	if(r<=mid){//範圍在左邊 
		return qsum(n*2,l,r);
	}
	else if(mid<l){//範圍在右邊 
		return qsum(n*2+1,l,r);
	}
	else{//一半在左,一半在右 
		return qsum(n*2,l,mid)+qsum(n*2+1,mid+1,r);
	}
}
int qmax(int n,int l,int r){
	if(l == a[n].l && r == a[n].r){//範圍相同,直接返回 
		return a[n].max;
	}
	int mid = (a[n].l+a[n].r)/2;
	if(r<=mid){//範圍在左邊 
		return qmax(n*2,l,r);
	}
	else if(mid<l){//範圍在右邊 
		return qmax(n*2+1,l,r);
	}
	else{//一半在左,一半在右 
		return MAX(qmax(n*2,l,mid),qmax(n*2+1,mid+1,r));
	}
}
int main(){
	int n,m;
	cin>>n>>m;
	build(1,1,n);
	for(int i =1;i<=n;i++){
		int x;
		cin>>x;
		insert(1,i,x);
	}
	for(int i =0;i<m;i++){
		int p,a,b;
		cin>>p>>a>>b;
		switch(p){
			case 1:change(1,a,b); break;
			case 2:cout<<qsum(1,a,b)<<endl; break;
			case 3:cout<<qmax(1,a,b)<<endl; break;
		}
	}
	return 0;
}

 

import java.util.Scanner;

public class 藍橋杯_操作格子 {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		m = in.nextInt();
		tree = new Segtree[4*n+5];
		for(int i=1;i<=4*n+4;i++)
			tree[i] = new Segtree();
		buildtree(1, 1, n);
		for(int i=1;i<=n;i++)
			insert(1, i, in.nextInt());;

		while(m-->0) {
			int Q = in.nextInt();
			int x = in.nextInt();
			int y = in.nextInt();
			if(Q==1) 
				updata(1, x, y);
			else if(Q==2) 
				System.out.println(querySum(1, 1, n, x, y));
			else if(Q==3)
				System.out.println(queryMax(1, 1, n, x, y));

		}
		
	}
	
	static int n,m;
	static Segtree[] tree;
	
	
	static class Segtree {
		int l,r,sum,max;
		
		public Segtree(int l,int r) {
			this.l = l;
			this.r = r;
		}
		public Segtree() {}
	}
	
	static void buildtree(int now,int l,int r) {
		tree[now].l = l;
		tree[now].r = r;
		if(l==r) 
			return;

		int mid = l + (r-l)/2;
		buildtree(2*now, l, mid);
		buildtree(2*now+1, mid+1, r);
//		tree[now].sum = tree[2*now].sum + tree[2*now+1].sum;
//		tree[now].max = Math.max(tree[2*now].max, tree[2*now+1].max);
	}
	static void insert(int now,int pos,int num){
		tree[now].sum+=num;
		tree[now].max=Math.max(tree[now].max, num);
		if(tree[now].l == tree[now].r)
			return;
		
		int mid = tree[now].l + (tree[now].r-tree[now].l)/2;
		if(pos<=mid)
			insert(2*now, pos, num);
		else
			insert(2*now+1, pos, num);

	}

	static void updata(int now,int pos,int num){
		if(tree[now].l == tree[now].r) {
			tree[now].sum=num;
			tree[now].max=num;			
			return;
		}
		
		int mid = tree[now].l + (tree[now].r-tree[now].l)/2;
		if(pos<=mid)
			updata(2*now, pos, num);
		else
			updata(2*now+1, pos, num);
		tree[now].sum = tree[2*now].sum + tree[2*now+1].sum;
		tree[now].max = Math.max(tree[2*now].max, tree[2*now+1].max);
	}
	
	

	static int querySum(int now,int l,int r,int x,int y) {
		if(r<x || l>y)
			return 0;
		if(x<=l && y>=r)
			return tree[now].sum;
		
		int mid = l + (r-l)/2;
		int ans = 0;
		if(x<=mid)
			ans+=querySum(2*now, l, mid, x, y);
		if(y>mid)
			ans+=querySum(2*now+1, mid+1, r, x, y);
		return  ans;
	}
	static int queryMax(int now,int l,int r,int x,int y) {
		if(y<l || x>r)
			return -1;
		if(x<=l && y>=r)
			return tree[now].max;
		
		int mid = l + (r-l)/2;
		int ans = -1;
		if(x<=mid)
			ans = Math.max(ans, queryMax(2*now, l, mid, x, y));
		if(y>mid)
			ans = Math.max(ans, queryMax(2*now+1, mid+1, r, x, y));
		return  ans;
	}
	
}

下面這個也一樣是30%,其實原則上沒上面的優化。不過沒多大區別

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		m = in.nextInt();
		tree = new Segtree[4*n+5];
		for(int i=1;i<=4*n+4;i++)
			tree[i] = new Segtree();
		buildtree(1, 1, n);
		for(int i=1;i<=n;i++)
			insert(1, i, in.nextInt());;

		while(m-->0) {
			int Q = in.nextInt();
			int x = in.nextInt();
			int y = in.nextInt();
			if(Q==1) 
				insert(1, x, y);
			else if(Q==2) 
				System.out.println(querySum(1, 1, n, x, y));
			else if(Q==3)
				System.out.println(queryMax(1, 1, n, x, y));

		}
		
	}
	
	static int n,m;
	static Segtree[] tree;
	
	
	static class Segtree {
		int l,r,sum,max;
		
		public Segtree(int l,int r) {
			this.l = l;
			this.r = r;
		}
		public Segtree() {}
	}
	
	static void buildtree(int now,int l,int r) {
		tree[now].l = l;
		tree[now].r = r;
		if(l==r) 
			return;

		int mid = l + (r-l)/2;
		buildtree(2*now, l, mid);
		buildtree(2*now+1, mid+1, r);
//		tree[now].sum = tree[2*now].sum + tree[2*now+1].sum;
//		tree[now].max = Math.max(tree[2*now].max, tree[2*now+1].max);
	}
	static void insert(int now,int pos,int num){
		if(tree[now].l == tree[now].r) {
			tree[now].sum=num;
			tree[now].max=num;			
			return;
		}
		
		int mid = tree[now].l + (tree[now].r-tree[now].l)/2;
		if(pos<=mid)
			insert(2*now, pos, num);
		else
			insert(2*now+1, pos, num);
		tree[now].sum = tree[2*now].sum + tree[2*now+1].sum;
		tree[now].max = Math.max(tree[2*now].max, tree[2*now+1].max);
	}

	
	
//	static int querySum(int now,int l,int r,int x,int y) {
//		if(r<x || l>y)
//			return 0;
//		if(x<=l && y>=r)
//			return tree[now].sum;
//		
//		int mid = l + (r-l)/2;
//		return querySum(2*now, l, mid, x, y) + querySum(2*now+1, mid+1, r, x, y);
//	}
	static int querySum(int now,int l,int r,int x,int y) {
		if(r<x || l>y)
			return 0;
		if(x<=l && y>=r)
			return tree[now].sum;
		
		int mid = l + (r-l)/2;
		int ans = 0;
		if(x<=mid)
			ans+=querySum(2*now, l, mid, x, y);
		if(y>mid)
			ans+=querySum(2*now+1, mid+1, r, x, y);
		return  ans;
	}
	static int queryMax(int now,int l,int r,int x,int y) {
		if(y<l || x>r)
			return -1;
		if(x<=l && y>=r)
			return tree[now].max;
		
		int mid = l + (r-l)/2;
		return Math.max(queryMax(2*now, l, mid, x, y), queryMax(2*now+1, mid+1, r, x, y));
	}
	
}

 

相關文章