不曉得這是不是線段樹的用法……

沒有測試用例、沒對極限數據進行處理,只是用最簡單的方式寫了一個通過標準測試的代碼

原題目是 >>> 對數組A[N],定義如下操作:

C x y : 將A[x] 修改爲y

L x y : 求區間[x,y]的左費用

R x y : 求區間[x,y]的右費用

其中左費用定義爲∑A(i)*(i-x+1),右費用定義爲∑A(i)*(y-i+1)

由於L和R操作的結果可能會非常大,因此要求計算結果對ie9+7取餘(我能說我不會嗎……)

1<=N<=1e5 ; 1<= A[i] <= 1000

 

 

class Main {
	
	// 處理輸入
	public static void main(String[] args) {
		System.out.println("hello https://tool.lu/");
		
		int[] data = {1,5,2,4,9,3,5,4,7,1,5,9};
		
		int[][] operate = {
			{'L'+0, 1, 3},
			{'C'+0, 1, 10},
			{'R'+0, 1, 3}
		};
		
		int[] results = new Main().solve(data, operate);
		
		for(int x : results) {
			System.out.print(x+"\t");
		}
		System.out.println();
	}
	
	// 處理操作
	public int[] solve(int[] data, int[][] operate) {
		
		int[] results = new int[operate.length];
		
		A a = A.create(data);
		
		for(int i=0; i<operate.length; ++i) {
			
			int[] op = operate[i];
			
			if(op[0] == 0+'C') {
				// update
				a.update(op[1], op[2]-data[op[1]]);
			} else if(op[0] == 0+'L') {
				// sumL
				results[i] = a.sumL(op[1], op[2]);
			} else if(op[0] == 0+'R') {
				// sumR
				results[i] = a.sumR(op[1], op[2]);
			} else {
				throw new RuntimeException("What the fuck?!!!");
			}
		}
		
		return results;
	}
	
	
}


class A {
	
	// 區間左右下標
	int left;
	int right;
	
	// 每個節點儲存當前節點的區間的Sum、L、R操作結果
	int areaSum;
	int areaL;
	int areaR;
	
	// 二叉樹
	A father;
	A son1;
	A son2;
	
	// to be delete
	boolean hasSon;
	
	// 對data數據的預處理
	public static A create(int[] data) {
		A a = new A();
		a.left = 0;
		a.right = data.length-1;
		// 區間爲雙含索引
		return a.create(data, a.left, a.right, a);
	}
	
	// this == father
	private A create(int[] data, int left, int right, A father) {
		
		// 節點下分至數組中的每個數上
		if(left == right) {
			father.areaSum = father.areaL = father.areaR = data[left];
			return father;
		} /*else if(right-left == 1) {
			father.areaSum = data[left] + data[right];
			father.areaL = data[left] + data[right]*2;
			father.areaR = data[left]*2 + data[right];
			return father;
		}*/
		
		A son1 = new A();
		A son2 = new A();
		
		int mid = (father.left+father.right)/2;
		
		son1.left = father.left;
		son1.right = mid;
		
		son2.left = mid+1;
		son2.right = father.right;
		
		father.son1 = create(data, son1.left, son1.right, son1);
		father.son2 = create(data, son2.left, son2.right, son2);
		
		father.hasSon = true;
		father.areaSum = son1.areaSum + son2.areaSum;
		father.areaL = son1.areaL + son2.areaL + son2.areaSum*(son2.left-son1.left);
		father.areaR = son1.areaR + son2.areaR + son1.areaSum*(son2.right-son1.right);
		
		return father;
	}
	
	
	// 參數increment是差值,在方法調用時傳入
	public void update(int i, int increment) {
		if(i>this.right || i<this.left) {
			return;
		}
		this.areaSum += increment;
		this.areaL += increment*(i-this.left+1);
		this.areaR += increment*(this.right-i+1);
		
		if(this.hasSon) {
			this.son1.update(i, increment);
			this.son2.update(i, increment);
		}
	}
	
	public int sumL(int x, int y) {
		if(y<x) {
			// not in this area
			return 0;
		}
		if(x==this.left && y==this.right) {
			// full case
			return this.areaL;
		}
		if(y<this.son2.left) {
			// full left
			return this.son1.sumL(x, y);
		}
		if(x>this.son1.right) {
			// full right
			return this.son2.sumL(x, y);
		}
		
		int sum2 = this.son2.sum(son2.left, y);
		
		int sumL1 = this.son1.sumL(x, son1.right);
		int sumL2 = this.son2.sumL(son2.left, y);
		
		return sumL1 + sumL2 + sum2*(son2.left-x);
	}
	
	public int sumR(int x, int y) {
		if(y<x) {
			// not in this area
			return 0;
		}
		if(x==this.left && y==this.right) {
			// full case
			return this.areaR;
		}
		if(y<this.son2.left) {
			// full left
			return this.son1.sumR(x, y);
		}
		if(x>this.son1.right) {
			// full right
			return this.son2.sumR(x, y);
		}
		
		int sum1 = this.son1.sum(x, son1.right);
		
		int sumR1 = this.son1.sumR(x, son1.right);
		int sumR2 = this.son2.sumR(son2.left, y);
		
		return sumR1 + sumR2 + sum1*(y-son1.right);
		
	}
	
	// sum of area(x,y)
	private int sum(int x, int y) {
				
		if(y<x) {
			return 0;
		}
		if(x==this.left && y==this.right) {
			return this.areaSum;
		}
		int sum1 = this.son1.sum(x, min(y,son1.right));
		int sum2 = this.son2.sum(max(x,son2.left), y);
		return sum1 + sum2;
	}
	
	
	// utils
	private int max(int a, int b) {
		return a>b?a:b;
	}
	private int min(int a, int b) {
		return a<b?a:b;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章