题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610
裸题。
注意到只有一次查找,那么查找的时候直接到叶子节点将叶子节点的值放到数组中,统计结果相当于离散化的一个过程。
对于这道题来说我们进行区间更新不需要像普通的那种求区间和的那样建立lazy标记,因为我们最后只关心叶子节点的值,故不需要lazy标记。
注意的地方,区间长度为[1,8000]在这个区间上进行操作。
如果某两段区间颜色相同,中间某一段没有颜色,这样算两段区间。
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=8e3+9;
int x[maxn<<2|1];
int sum[maxn];
void build(){
memset(x,-1,sizeof(x));
memset(sum,0,sizeof(sum));
}
void pushdown(int k){
if(x[k]!=-1){
x[k<<1]=x[k<<1|1]=x[k];
x[k]=-1;
}
}
void updata(int L,int R,int v,int l,int r,int k){
if(l>=L&&r<=R){
x[k]=v;
return ;
}
pushdown(k);
int mid=(l+r)>>1;
if(L<=mid) updata(L,R,v,l,mid,k<<1);
if(R>mid) updata(L,R,v,mid+1,r,k<<1|1);
//if(x[k<<1]==x[k<<1|1]) x[k]=x[k<<1];
//else x[k]=-1;
}
int xx[maxn];
int top;
void myfind(int l,int r,int k){
if(l==r){
xx[++top]=x[k];
return ;
}
pushdown(k);
int mid=(l+r)>>1;
myfind(l,mid,k<<1);
myfind(mid+1,r,k<<1|1);
}
int main(){
int m;
int l,r,x;
while(scanf("%d",&m)!=EOF){
top=0;
build();
while(m--){
scanf("%d%d%d",&l,&r,&x);
++l;
if(l>r) continue;
updata(l,r,x,1,8000,1);
}
myfind(1,8000,1);
for(int i=1;i<=top;++i)
if(i==1||xx[i]!=xx[i-1]) if(xx[i]!=-1) ++sum[xx[i]];
for(int i=0;i<=8000;++i)
if(sum[i]) printf("%d %d\n",i,sum[i]);
printf("\n");
}
return 0;
}