果然我不会的题都是大佬眼里的水题。。我好菜啊啊啊55555...
先附上大佬博客Orz:https://blog.youkuaiyun.com/zezzezzez/article/details/80230026
https://blog.youkuaiyun.com/u014779110/article/details/48784581
离散化其实看了大佬博客后就不难理解了,就是线段树QAQ...果然我还是没理解透彻啊。。。虽然是区间信息,但我怎么都不知道怎么用线段树555。。后来向某大佬请教Orz,突然明白了线段树存的是该位置当前由哪个海报占有,这个可以直接借助懒标记实现。查询操作只进行一次,当这个位置有海报(≠0)并且没出现过ans++,标记并return。
后来一直RE,一是因为数组开小了,二是因为线段树操作时r=toll不是n或tol(详见代码)
附上AC代码:(真不容易啊QAQ...)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
typedef pair<int,int>pp;
#define mkp make_pair
#define pb push_back
const double pi=acos(-1.0);
const double eps=1e-9;
const int INF=0x3f3f3f3f;
const ll MOD=1e9+7ll;
//数组开大一点,不然RE
const int MAX=5e4+10;
int n,m,ans;
struct node
{ int l,r,f;
}tree[8*MAX];
bool vis[2*MAX];
int zuo[MAX],you[MAX];
int tmp[2*MAX];
void build(int k,int l,int r) //建树
{
tree[k].l=l,tree[k].r=r;
tree[k].f=0;//tree[k].w=0;
if(tree[k].l==tree[k].r)
{ return; }
int m=(tree[k].l+tree[k].r)>>1;
build(k<<1,l,m);
build(k<<1|1,m+1,r);
}
void down(int k)//标记下传
{
tree[k<<1].f=tree[k].f;
tree[k<<1|1].f=tree[k].f;
//tree[k<<1].w=tree[k].f*(tree[k<<1].r-tree[k<<1].l+1);
//tree[k<<1|1].w=tree[k].f*(tree[k<<1|1].r-tree[k<<1|1].l+1);
tree[k].f=0;
}
void change_interval(int k,int a,int b,int y) //区间修改
{
if(tree[k].l>=a&&tree[k].r<=b)
{
//tree[k].w=(tree[k].r-tree[k].l+1)*y;
tree[k].f=y;//懒标记直接记录了该位置当前由哪个海报占有
return;
}
if(tree[k].f)
down(k);
int m=(tree[k].l+tree[k].r)>>1;
if(a<=m) change_interval(k<<1,a,b,y);
if(b>m) change_interval(k<<1|1,a,b,y);
}
void ask_interval(int k,int a,int b) //区间查询
{
if(tree[k].f)//有海报
{
if(!vis[tree[k].f])//未出现过
{
ans++;
vis[tree[k].f]=true;
}
return;
}
if(tree[k].l==tree[k].r)
return;
if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)>>1;
if(a<=m) ask_interval(k<<1,a,b);
if(b>m) ask_interval(k<<1|1,a,b);
}
int main()
{
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
int x,y;
scanf("%d",&n);
memset(vis,false,sizeof(vis));
//离散化
memset(tmp,0,sizeof(tmp));
int tol=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&zuo[i],&you[i]);
tmp[++tol]=zuo[i];
tmp[++tol]=you[i];
}
sort(tmp+1,tmp+1+tol);
int toll=unique(tmp+1,tmp+1+tol)-tmp-1;
int tt=toll;
for(int i=2;i<=tt;i++)//注意此处循环!
{
if(tmp[i]-tmp[i-1]>1)
tmp[++toll]=tmp[i-1]+1;
}
sort(tmp+1,tmp+1+toll);
build(1,1,toll);//注意此处建树且为toll不是n!
for(int i=1;i<=n;i++)
{
x=lower_bound(tmp+1,tmp+1+toll,zuo[i])-tmp;//注意为toll不是tol!
y=lower_bound(tmp+1,tmp+1+toll,you[i])-tmp;
//cout<<"x="<<x<<" y="<<y<<endl;
change_interval(1,x,y,i);
}
ans=0;
ask_interval(1,1,toll);//注意为toll不是n!
printf("%d\n",ans);
}
return 0;
}