UVa 1232 / LA 4108 線段樹

         這題就是個裸的線段樹。。但細節容易想錯。。

        題意:一個全0的序列,m次操作,每次給出一個區間[l,r)和一個值v,將該區間內所有小於等於v的數全部修改爲v。求總的修改次數。

        怎麼做呢?一開始我是這麼做的:開一個線段樹,每個節點維護一個值:該區間內的元素的值——如果該區間內元素值不同,則置爲-1,然後直接統計。(而且一開始我居然把1-4*maxn內的所有點都初始化了一遍。。)這樣做最壞情況下每次都要O(4*n),當然華麗麗地T

        怎麼優化呢?其實很好想:如果當前區間內的最小值都比v大,那麼就無需繼續了;如果當前區間內的最大值都比v小,那就直接把整個區間改成v好了;如果v介於maxvminv之間,那麼繼續往下找。這樣一來,連這個區間內的元素值是否相同這個標記都省去了——因爲如果相同,則有maxv=minvv要麼比這個值大,要麼比這個值小,不會再遞歸下去了。

         Attention!說過了,這道題細節很容易想錯:我們應該在哪些地方調用updatepushdownmaintain?注意這道題的maintain不是通常意義上的maintain——後者是用父親維護兒子,而前者是用兒子維護父親。所以,這裏的maintainpushup更爲恰當。所以,update僞代碼如下:


        注意,對於沒有遞歸訪問的子樹,沒有調用push_up,否則將造成無中生有的節點。


// LA4108

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

 const int N=120000, INF=0x6f6f6f6f;

 #define rep(i,a,b) for (int i=a; i<=b; i++)

 int a[N], b[N], t[N], minv[4*N], maxv[4*N], y1, y2, h, len;

 void read(int &r) {
	int x=0, f=1;
	char ch=getchar();
	while (ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
	while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
	r=x*f;
 }

 void build(int o, int L, int R) {
 	minv[o]=maxv[o]=0;
 	if (L==R) return;
 	int M=(L+R)>>1, lc=o<<1, rc=lc|1;
 	if (L<=M) build(lc, L, M);
 	if (M<R) build(rc, M+1, R);
 }

 void maintain(int o, int L, int R) {
 	if (L>=R) return;
 	int lc=o<<1, rc=lc|1;
 	maxv[o]=max(maxv[lc], maxv[rc]);
 	minv[o]=min(minv[lc], minv[rc]);
 }
 
 void pushdown(int o) {
 	if (maxv[o]!=minv[o]) return;
 	int lc=o<<1, rc=lc|1;
 	maxv[lc]=minv[lc]=maxv[rc]=minv[rc]=maxv[o];
 }

 void update(int o, int L, int R) {
 	int lc=o<<1, rc=lc|1, ok=(y1<=L && R<=y2);
 	if (h<minv[o]) return;
 	if (ok && maxv[o]<=h) {
 		maxv[o]=minv[o]=h;
 		len+=(R-L+1);
 		return;
 	}
 	if (L<R) pushdown(o);
 	int M=(L+R)>>1;
 	if (y1<=M) update(lc, L, M);
 	if (M<y2) update(rc, M+1, R); 
 	maintain(o, L, R);
 }

int T, ans, n, minl, maxr;
int main()
{
	read(T);
	while (T--) {
		read(n);
		minl=INF, maxr=-INF, ans=0;
		rep(i,1,n) { 
			read(a[i]), read(b[i]), read(t[i]);
			b[i]--;
			minl=min(minl, a[i]);
			maxr=max(maxr, b[i]);
		}
		build(1, minl, maxr);
		maxv[1]=minv[1]=0;
		rep(i,1,n) {
			y1=a[i], y2=b[i], h=t[i], len=0;
			update(1, minl, maxr); 
			ans+=len;
		}
		printf("%d\n", ans);
	}
	
	return 0;
}


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