這題就是個裸的線段樹。。但細節容易想錯。。
題意:一個全0的序列,m次操作,每次給出一個區間[l,r)和一個值v,將該區間內所有小於等於v的數全部修改爲v。求總的修改次數。
怎麼做呢?一開始我是這麼做的:開一個線段樹,每個節點維護一個值:該區間內的元素的值——如果該區間內元素值不同,則置爲-1,然後直接統計。(而且一開始我居然把1-4*maxn內的所有點都初始化了一遍。。)這樣做最壞情況下每次都要O(4*n),當然華麗麗地T。
怎麼優化呢?其實很好想:如果當前區間內的最小值都比v大,那麼就無需繼續了;如果當前區間內的最大值都比v小,那就直接把整個區間改成v好了;如果v介於maxv和minv之間,那麼繼續往下找。這樣一來,連這個區間內的元素值是否相同這個標記都省去了——因爲如果相同,則有maxv=minv,v要麼比這個值大,要麼比這個值小,不會再遞歸下去了。
Attention!說過了,這道題細節很容易想錯:我們應該在哪些地方調用update、pushdown和maintain?注意這道題的maintain不是通常意義上的maintain——後者是用父親維護兒子,而前者是用兒子維護父親。所以,這裏的maintain用pushup更爲恰當。所以,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;
}