题目大意:
每次往墙上li - ri的范围涂色,每次涂得颜色不一样,后涂的会覆盖前面的,求最终墙上有几种颜色
思路:
将所有端点离散化建立一课线段树,树上每个节点代表这个节点覆盖的范围以及是否被涂色,逆序将所有序列覆盖线段树上的节点,若有节点是空的,则代表最终有这个颜色,标记覆盖后的节点,若没有可以覆盖的节点,则此颜色最终不会出现
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#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 = 100000;
int t,n,ans;
struct node{
int l,r;
bool covered;
}p[maxn<<1];
bool lazy[maxn<<1];
int l[maxn],r[maxn];
vector<int> v;
void pushup(int rt)
{
p[rt].l = p[rt<<1].l;
p[rt].r = p[rt<<1|1].r;
p[rt].covered = p[rt<<1].covered && p[rt<<1|1].covered;
}
void pushdown(int rt)
{
if(lazy[rt])
{
lazy[rt<<1] = true;
lazy[rt<<1|1] = true;
p[rt<<1].covered = true;
p[rt<<1|1].covered = true;
}
}
void build(int l,int r,int rt)
{
if(l == r)
{
p[rt].l = v[l-1];
p[rt].r = v[l-1];
p[rt].covered = false;
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
int post(int L,int R,int rt)
{
if(p[rt].l >= L && p[rt].r <= R)
{
if(p[rt].covered) return 0; //已被覆盖
else //可覆盖节点
{
p[rt].covered = true;
lazy[rt] = true;
return 1;
}
}
pushdown(rt);
int res = 0;
if(L <= p[rt<<1].r && !p[rt<<1].covered) res = max(res,post(L,R,rt<<1));
if(R >= p[rt<<1|1].l && !p[rt<<1|1].covered) res = max(res,post(L,R,rt<<1|1));
pushup(rt);
return res;
}
int main()
{
scanf("%d",&t);
while(t--)
{
v.clear();
Clr(lazy);
Clr(l);
Clr(r);
scanf("%d",&n);
LP(0,n)
{
scanf("%d%d",&l[i],&r[i]);
v.push_back(l[i]);
v.push_back(r[i]);
}
sort(v.begin(),v.end());
int num = unique(v.begin(),v.end()) - v.begin(); //所有端点数量
build(1,num,1); //建树
int ans = 0;
LP2(n-1,0) ans += post(l[j],r[j],1);
printf("%d\n",ans);
}
}