欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-01 21:02:14
...

题意:

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

思路:

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

代码:

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int mod=998244353;
const int maxm=500005;
typedef pair <int ,int >P;
struct nn
{
    int l,r,id;
    bool friend operator <(nn a,nn b)
    {
        if(a.l==b.l)
            return a.r<b.r;
        return a.l<b.l;
    }
}a[200005];
ll res,num;
int ans[200005];
vector <int >v;
#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<d)return ;
	if(tree[rt].l==tree[rt].r)
    {
        num++;//破坏个数增加
        tree[rt].v=-inf;//更新为-inf
        ans[tree[rt].id]=t;
        if(res==0)res=1;
        res=res*tree[rt].id%mod;//维护res
        return ;
    }
	int mid=(tree[rt].l+tree[rt].r)>>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;
}


 

相关标签: 神奇的线段树