1. 程式人生 > >洛谷P3616 富金森林公園題解(樹狀陣列)

洛谷P3616 富金森林公園題解(樹狀陣列)

P3616 富金森林公園

題目描述

博艾的富金森林公園裡有一個長長的富金山脈,山脈是由一塊塊巨石並列構成的,編號從1到N。每一個巨石有一個海拔高度。而這個山脈又在一個盆地中,盆地裡可能會積水,積水也有一個海拔高度,所有嚴格低於這個海拔高度的巨石,就會在水面下隱藏。

由於地殼運動,巨石的海拔高度可能會隨時變化,每次一塊的巨石會變成新的海拔高度。當然,水面的高度也會隨時發生變化。

因為有這樣奇妙的地質奇觀,吸引了很多遊客來遊玩。uim作為一個遊客,可以告訴你此時水位海拔,你得告訴他,能看到有幾個連續露出水面的部分。(與水面持平我們也認為是露出) 輸入輸出格式 輸入格式:

第一行兩個整數N和M,分別表示N塊石頭,M個詢問。

接下來一行,N個整數Ai表示每個巨石的初始海拔。

接下來M行,每行有兩個或者三個數,每一行如果第一個數是1,那麼後面跟一個Bj,表示水面海拔。如果第一個數是2,後面跟兩個整數,Cj和Dj,表示編號Cj的巨石海拔變為Dj。

輸出格式:

對於每個"1"詢問,給出一個整數答案,也就是露出了幾部分的山峰。

輸入輸出樣例

輸入樣例#1:

5 4 8 6 3 5 4 1 5 2 4 1 1 5 1 3

輸出樣例#1:

2 1 2

說明

10%的資料, N,M<=2000

另外30%的資料, 只有"1"的詢問。

100%的資料, 1<=N,M<=200000,1<=Ai,Bj,Dj<=10^9,一定有"1"詢問

這題解法還是挺巧妙的

先考慮暴力

對於水平面高度為x 當h[i-1] < x <= h[i]時 ans++

正解: 觀察暴力, 對於h[i], h[i-1] 我們就給ans[h[i-1]+1 ~ h[i]] 加1 那麼我們可以先對所有高度離散化一下,再搞一顆樹狀陣列或線段樹, 區間修改單點詢問

code:

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;

struct node {
 	int v, id;
 	bool flag; // 0山的高度 1詢問出現的高度 
 	bool operator <(node z) const {
	 	return v < z.v;
	}
}h[N<<1];

struct question {
	int k, c, d;
}q[N];
int a[N];
#define lowbit(x) (x&(-x))
int t[N<<1], n, m, s;
inline void add(int x, int k) {
	while (x <= s) {
		t[x] += k;
		x += lowbit(x);
	}
	return ;
}
inline int get(int x) {
	int sum = 0;
	while (x) {
		sum += t[x];
		x -= lowbit(x);
	}
	return sum;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		h[i].id = i;
		scanf("%d", &h[i].v);
	}
	for (int i = 1; i <= m; i++) {
		scanf("%d", &q[i].k);
		if (q[i].k == 1)
			scanf("%d", &q[i].d);
		else scanf("%d%d", &q[i].c, &q[i].d);
		h[i+n].id = i; h[i+n].flag = 1;
		h[i+n].v = q[i].d;
	}
	sort(h+1, h+1+n+m);
	s = 0;
	for (int i = 1; i <= m+n; i++) {
		if (h[i].v != h[i-1].v || i == 1) s++;
		if (!h[i].flag)
			a[h[i].id] = s;
		else q[h[i].id].d = s;
	}
	for (int i = 1; i <= n; i++)
		if (a[i] > a[i-1]) add(a[i-1]+1, 1), add(a[i]+1, -1);
	for (int i = 1; i <= m; i++) {
		if (q[i].k == 1)
			printf("%d\n", get(q[i].d));
		else {
			if (a[q[i].c] > a[q[i].c-1]) add(a[q[i].c-1]+1, -1), add(a[q[i].c]+1, 1);
			if (a[q[i].c+1] > a[q[i].c]) add(a[q[i].c]+1, -1), add(a[q[i].c+1]+1, 1);
			a[q[i].c] = q[i].d;
			if (a[q[i].c] > a[q[i].c-1]) add(a[q[i].c-1]+1, 1), add(a[q[i].c]+1, -1);
			if (a[q[i].c+1] > a[q[i].c]) add(a[q[i].c]+1, 1), add(a[q[i].c+1]+1, -1);
		}
	}
	return 0;
}