题意:
现在有n个线段,每个线段有一种颜色,定义一对线段是“坏的”,当且仅当这对线段i,j满足以下条件:
1.c[i]!=c[j]
2.i和j相交(包括边界)
问你最多能选择多少线段使得其中没有任何一对线段是坏的
题解:
先后想了三种方法,花了我两个半小时
接下来假设颜色为0,1
首先我得到一个结论,就是c[i]只会从c[i]^1的地方转移过来。
因为如果从相同颜色的地方转移过来,会有很多很烦的情况(或许是我菜了),刷掉了我前两个想法。
那么怎么找这个转移的位置,可以用线段树来查询最大值。
因为我们是从相反颜色转移过来的,所以这个转移的位置后面可能会有一些相同颜色的线段,当然这两个要合在一起才能查询最大值。
那么我们只需要在这个做之前,对c[i]^1这棵线段树的0~e[i].l-1区间+1即可。
最后还需要更新c[i]线段树的e[i].r位置。
当然这是两种更新,我们需要不同处理方法:
有人可能会问,为什么在op=1的时候,不需要加上那些+1的线段。
因为我是按右端点排序的,所以+1的那些位置一定不会影响到后面的点,因此不需要处理这种情况。
#include<bits/stdc++.h>
using namespace std;
#define pa pair<int,int>
const int N=6e5+5;
struct Segment_Tree{
int mx[N*4],ad[N*4],f[N*4];
void push_down(int root){
if(!f[root])return ;
mx[root<<1]+=f[root];
mx[root<<1|1]+=f[root];
f[root<<1]+=f[root];
f[root<<1|1]+=f[root];
f[root]=0;
}
void update(int l,int r,int root,int ql,int qr,int op,int v){
if(l>=ql&&r<=qr){
if(op==1)
mx[root]=max(mx[root],v);
else
mx[root]+=v,f[root]+=v;
return ;
}
push_down(root);
int mid=l+r>>1;
if(mid>=ql)
update(l,mid,root<<1,ql,qr,op,v);
if(mid<qr)
update(mid+1,r,root<<1|1,ql,qr,op,v);
mx[root]=max(mx[root<<1],mx[root<<1|1]);
}
int query(int l,int r,int root,int ql,int qr){
if(l>=ql&&r<=qr)return mx[root];
push_down(root);
int mid=l+r>>1;
int ans=0;
if(mid>=ql)
ans=query(l,mid,root<<1,ql,qr);
if(mid<qr)
ans=max(ans,query(mid+1,r,root<<1|1,ql,qr));
return ans;
}
}t[2];
struct edge{
int l,r,c;
bool operator< (const edge& a)const {
return r<a.r;
}
}e[N];
int a[N*2];
int main()
{
int n,tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].c),e[i].c--,a[++tot]=e[i].l,a[++tot]=e[i].r;
sort(a+1,a+1+tot);
tot=unique(a+1,a+1+tot)-a-1;
sort(e+1,e+1+n);
for(int i=1;i<=n;i++){
e[i].l=lower_bound(a+1,a+1+tot,e[i].l)-a;
e[i].r=lower_bound(a+1,a+1+tot,e[i].r)-a;
}
int ans=0,val,num[2]={0};
for(int i=1;i<=n;i++){
int col=e[i].c;
num[col]++;
t[col^1].update(0,tot,1,0,e[i].l-1,2,1);
val=0;
val=t[col^1].query(0,tot,1,0,e[i].l-1);
val=max(num[col],val);
t[col].update(0,tot,1,e[i].r,e[i].r,1,val);
ans=max(ans,val);
}
printf("%d\n",ans);
return 0;
}