题目大意:
一维坐标系上有n条线段,每条线段都有 l r 。每次破坏一个点x 所有包含这个点x 的线段都会被破坏。现在要求你针对每次询问输出每次有多少条线段被破坏,被破坏过的线段不能被破坏(强制在线)。
m次询问完后统一输出每条线段分别是在第多少次操作后被破坏的,没有被破坏的输出0。
解题思路:
比赛的时候想到了 一种思路,就是按照每条线段的左端点排序,然后针对右端点建立主席树,每次查询有多少右端点大于等于x值,但是当时发现主席树的修改很麻烦,然后没有写出来。
结果赛后发现是真的智障了,干嘛要建主席数,问了我校主席cyh,他也是先按照左端点排序,然后直接针对右端点建立线段树即可。因为我们可以二分找到我们每次需要查询的 l r,在 l r 这个区间内,直接查询有多少val大于x 并且把val更新为-INF即可,每个结点保存右端点最大值。
Ac代码:
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define rank ra
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int INF=1e9+7;
const int mod=998244353;
int n,m,r,num,rank[maxn]; //rank表示i条线段什么时候被破坏
ll res;
vector<int> v;
struct node //线段
{
int l,r,idx;
bool operator<(const node &p) const
{
if(l==p.l) return r<p.r;
return l<p.l;
}
}a[maxn];
struct Node //线段树结点
{
int l,r,mid,id; //以及最大值对应的线段
int val; //最大值
}t[maxn<<2];
void pushup(int rt) //维护最大值 以及 线段编号
{
t[rt].val=max(t[lson].val,t[rson].val);
if(t[lson].val>=t[rson].val) t[rt].id=t[lson].id;
else t[rt].id=t[rson].id;
}
void build(int l,int r,int rt)
{
int mid=(l+r)>>1;
t[rt].l=l,t[rt].r=r,t[rt].mid=mid;
if(l==r)
{
t[rt].val=a[l].r;
t[rt].id=a[l].idx;
return ;
}
build(l,mid,lson);
build(mid+1,r,rson);
pushup(rt);
}
void update(int l,int r,int x,int ti,int rt) //查询以及更新
{
if(l>r) return ;
if(t[rt].val<x) return ; //小于 x return
if(t[rt].l==t[rt].r)
{
num++;
t[rt].val=-INF;
rank[t[rt].id]=ti;
if(res==0) res=1;
res=res*t[rt].id%mod; //维护res
return ;
}
if(l<=t[rt].mid) update(l,r,x,ti,lson);
if(r>t[rt].mid) update(l,r,x,ti,rson);
pushup(rt);
}
int main()
{
int QAQ,kase=0;
scanf("%d",&QAQ);
while(QAQ--)
{
v.clear();
memset(rank,0,sizeof rank);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].l,&a[i].r),a[i].idx=i,v.push_back(a[i].l);
sort(a+1,a+1+n),sort(v.begin(),v.end()); //对线段排序
build(1,n,1);
int ti=1; num=0; res=0;
printf("Case #%d:\n",++kase);
while(m--)
{
int x; scanf("%d",&x);
x=x^res;
//printf("--%d %lld\n",x,res);
auto it=upper_bound(v.begin(),v.end(),x); //找出应该查询的区间 r
if(it==v.end()) r=n;
else if(it==v.begin()) r=0;
else r=it-v.begin();
num=0; res=0;
update(1,r,x,ti++,1);
printf("%d\n",num);
}
for(int i=1;i<=n;i++)
printf("%d%c",rank[i]," \n"[i==n]);
}
//system("pause");
}