题目大意:
每次给[l,r)区间涂色c,后涂覆盖之前的,求最后有哪些颜色,分别有多少段
思路:
区间赋值,用线段树。
PS:每次涂色是 l ~ r 的区间,而不是涂点,最开始一直看不懂样例,看了大佬们的题解才发现题目意思理解错了。所以将保存颜色的color[i]定义为[i,i+1)的颜色,故每次更新操作更新的区间是 [l, r - 1]
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#define Clr(x) memset(x,0,sizeof(x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define INF 0x33333333
#define LP(x,y) for(int i = x; i < y; i++)
#define LP2(x,y) for(int j = x; j >= y; j--)
using namespace std;
typedef long long LL;
//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int maxn = 8010;
int color[maxn<<2],lazy[maxn<<2]; //color[i]代表[i,i+1)的颜色
vector<int> vi;
map<int,int> mii;
int n,l,r,c;
void pushdown(int rt)
{
if(lazy[rt] != -1)
{
color[rt<<1] = lazy[rt];
color[rt<<1|1] = lazy[rt];
lazy[rt<<1] = lazy[rt];
lazy[rt<<1|1] = lazy[rt];
lazy[rt] = -1;
}
}
void update(int L,int R,int C,int l,int r,int rt)
{
if(l >= L && r <= R)
{
color[rt] = C;
lazy[rt] = C;
return;
}
int m = (l + r) >> 1;
pushdown(rt);
if(L <= m) update(L,R,C,lson);
if(R > m) update(L,R,C,rson);
}
void solve(int l,int r,int rt)
{
if(l == r)
{
vi.push_back(rt);
return;
}
int m = (l + r) >> 1;
pushdown(rt);
solve(lson);
solve(rson);
}
void init()
{
memset(color,-1,sizeof(color));
memset(lazy,-1,sizeof(lazy));
vi.clear();
mii.clear();
}
int main()
{
while(~scanf("%d",&n))
{
init();
LP(1,n+1)
{
scanf("%d%d%d",&l,&r,&c);
update(l+1,r,c,1,8001,1); //更新是r要-1
}
solve(1,8001,1);
int pre = color[vi[0]];
mii[color[vi[0]]]++;
for(int i = 1; i < vi.size(); i++)
{
if(color[vi[i]] == pre) continue;
else
{
pre = -1;
if(color[vi[i]] != -1)
{
pre = color[vi[i]];
mii[color[vi[i]]]++;
}
}
}
for(int i = 0; i <= 8000; i++)
{
if(mii.count(i)printf("%d %d\n",i,mii[i]);
}
printf("\n");
}
}