牛客网暑期ACM多校训练营(第六场)-- I-Team Rocket

题意:

有n条线段,每条线段都有l,r。每次破坏一个点x所有包含这个点x 的线段都会被破坏。现在要求你输出每次有多少条线段被破坏,被破坏过的线段不能被破坏(强制在线)。m次询问完后统一输出每条线段分别是在第多少次操作后被破坏的,没有被破坏的输出0。

思路:

先按照左端点排序,然后直接针对右端点建立线段树即可。因为我们可以二分找到我们每次需要查询的l,r在l,r这个区间内,直接查询有多少v大于x 并且把v更新为-inf即可,每个结点保存右端点最大值。统计答案的时候可以在更新答案的时候一并统计。

代码:

#include 
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int mod=998244353;
const int maxm=500005;
typedef pair P;
struct nn
{
    int l,r,id;
    bool friend operator <(nn a,nn b)
    {
        if(a.l==b.l)
            return a.rv;
#define MAXN 200010
struct node {
	int l,r;
	int v,id;
}tree[MAXN<<4];
void pushup(int rt)
{
    tree[rt].v=max(tree[rt<<1].v,tree[rt<<1|1].v);
    if(tree[rt<<1].v>=tree[rt<<1|1].v)tree[rt].id=tree[rt<<1].id;
    else tree[rt].id=tree[rt<<1|1].id;
}
void build(int l, int r,int rt)
{
    tree[rt].l=l,tree[rt].r=r;
	if (l==r){
		tree[rt].v=a[l].r;
		tree[rt].id=a[l].id;
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
	pushup(rt);
}
void update(int l, int r, int d,int t,int rt)
{
	if(l>r)return ;
	if(tree[rt].v>1;
	if (l<=mid)update(l,r,d,t,rt<<1);
	if (r>mid)update(l,r,d,t,rt<<1|1);
	pushup(rt);
}
int main()
{
    int ca;
    scanf("%d",&ca);
    for(int jj=1;jj<=ca;jj++)
    {
        v.clear();
        memset(ans,0,sizeof ans);
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&a[i].l,&a[i].r),a[i].id=i,v.push_back(a[i].l);
        sort(a+1,a+n+1);sort(v.begin(),v.end());
        int tt=1;res=0;
        build(1,n,1);
         printf("Case #%d:\n",jj);
        while(m--)
        {
            int x;
            scanf("%d",&x);
            x=x^res;
            int k=upper_bound(v.begin(),v.end(),x)-v.begin();//找到第一个大于x的左端点的下标
            num=0,res=0;
            update(1,k,x,tt++,1);
            printf("%d\n",num);
        }
        for(int i=1;i<=n;i++)
            printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}


 

你可能感兴趣的:(线段树)