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

题意:

给定n个区间, m次询问, 每次询问给一个点, 问这个点在哪些区间内, 然后删掉这些区间。

分析:

将n个区间按L大小升序排列, 然后将这些区间视为点构建一棵n个点的线段树, 树的节点记录这个区间的[l, r] 和按题目输入顺序排列的index

只有叶子节点的l, r代表这个区间本身, 他们的父亲更新他们儿子的最大r用于剪枝 (如果这个点所有儿子的最大R都小于查询的点, 就不用查了)

接下来只要二分出左区间大于x的那个区间的pos, 那么查询区间就是(1~pos)中有哪些点的右区间大于x, 记录答案并修改右区间即可。 

#include <bits/stdc++.h>
using namespace std;
const int maxN = 2e5 + 7;
const int INF = 2e9 + 7;
int n, m, x, y, pos, t, cancel;
long long res;
int ans[maxN];
struct Interval {
    int l, r, index;
    bool operator < (const Interval& a)const {
        return l < a.l;
    }
} travel[maxN], tree[maxN * 4];
  
void build(int treeIndex, int L, int R) {
//    printf("%d %d\n", L , R);
    if(L == R) {
        tree[treeIndex].l = travel[L].l;
        tree[treeIndex].r = travel[L].r;
        tree[treeIndex].index = travel[L].index;
        return;
    }
    int mid = (L + R) / 2;
    int lSon = treeIndex * 2, rSon = treeIndex * 2 + 1;
    build(lSon, L, mid);
    build(rSon, mid + 1, R);
    tree[treeIndex].r = max(tree[lSon].r, tree[rSon].r);
}
  
void query(int treeIndex, int L, int R) {
    if(tree[treeIndex].r < x)
        return;
    if(L == R) {
        cancel++;
        int inIndex = tree[treeIndex].index;
        res = ((long long)res * inIndex) % 998244353;
        tree[treeIndex].r = -INF;
        ans[inIndex] = t;
        return;
    }
     
    int mid = (L + R) / 2;
    int lSon = treeIndex * 2, rSon = treeIndex * 2 + 1;
    query(lSon, L, mid);
    if(pos > mid)
        query(rSon, mid + 1, R);
    tree[treeIndex].r = max(tree[lSon].r, tree[rSon].r);
}
  
int main() {
//    freopen("data.txt","r", stdin);
//    freopen("3.txt","w", stdout);
    int T;
    scanf("%d", &T);
    for(int kase = 1; kase <= T; kase++) {
        printf("Case #%d:\n", kase);
        memset(ans, 0, sizeof(ans));
        memset(tree, 0, sizeof(tree));
        memset(travel, 0 , sizeof(travel));
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= n; i++) {
            scanf("%d %d", &travel[i].l, &travel[i].r);
            travel[i].index = i;
        }
        sort(travel + 1, travel + 1 + n);
//        for(int i = 1; i <= n; i++) printf("%d %d\n", travel[i].l, travel[i].r);
        build(1, 1, n);
        res = 0;
        for(t = 1; t <= m; t++) {
            scanf("%d", &y);
            x = y ^ res;
            pos = upper_bound(travel + 1, travel + 1 + n, (Interval) {x,0,0}) - (travel + 1);
            cancel = 0, res = (long long)1;//乘积初始化为1
            if(pos > 0) // pos等于0说明没有任何一个左区间比x小
                query(1, 1, n);//int treeIndex,  int L, int R
            printf("%d\n", cancel);
            if(!cancel)
                res = 0;
        }
  
  
  
        printf("%d", ans[1]);
        for(int i = 2; i <= n; i++) {
            printf(" %d", ans[i]);
        }
        printf("\n");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Jadon97/p/9432236.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值