gym -101864 - B . A Leap of Faith (线段树求相交区间个数)

链接:B - A Leap of Faith

题意:
给 n 个 A类区间和 m 个 B 类区间,区间的左右端点为 l , r. 给出 q 次修改,每次询问加入一个 A 类区间或者 B 类区间,求每次修改后有交集的A 类与B类区间的对数。

思路:

  1. 求与 【l , r】区间相交的区间个数,可以先求出与它不相交的区间个数,也就是右端点比 l 小 ,或者左端点比 r 大的区间的个数(这个经常用),然后就可以用线段树维护,把区间的几个端点用4个线段树维护,就可以很快求出区间个数。
  2. 所以初始答案,我们只需要遍历 n 个 A 类区间,求出 B 中与它相交的个数。修改的时候只要相应的用线段树查询一下就好了。注意要离散化。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<cstring>
#include<bitset>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=4e6+7;
const int rr = 233;
const int mod = 1e9 + 7;
int T;
int sum[6][maxn];
int n,m,q;
int l1[maxn],l2[maxn],r1[maxn],r2[maxn],val[maxn],k;
struct node{
    
    
    int id,l,r;
}num[maxn];
void pushdown(int rt){
    
    
    for(int i = 1; i <= 4; i ++){
    
    
        sum[i][rt] = (sum[i][rt << 1] + sum[i][rt << 1 | 1]);
    }
    return ;
}
void update(int id,int pos,int l,int r,int rt){
    
    
    if(l == r){
    
    
        sum[id][rt] ++;
        return ;
    }
    int mid = (l + r) / 2;
    if(pos <= mid) update(id,pos,l,mid,rt << 1);
    if(pos > mid) update(id,pos,mid + 1 ,r ,rt << 1|1);
    pushdown(rt);
}
int query(int id,int L,int R,int l,int r,int rt){
    
    
    int s = 0;
    if(L <= l && R >= r){
    
    
        return sum[id][rt];
    }
    int mid = (l + r) / 2;
    if(L <= mid) s += query(id,L,R,l,mid,rt << 1);
    if(R > mid) s += query(id,L,R,mid + 1,r,rt << 1 | 1);
    return s;
}
int main (){
    
    
    scanf("%d",&T);
    int TT = T;
    int tot = 1;
    while(T--){
    
    
        scanf("%d",&n);
        k = 0;
        for(int i = 1; i <= n ; i++){
    
    
            scanf("%d%d",&l1[i],&r1[i]);
            val[k++] = l1[i];
            val[k++] = r1[i];
        }
        scanf("%d",&m);
        for(int i = 1; i <= m ; i++){
    
    
            scanf("%d%d",&l2[i],&r2[i]);
            val[k++] = l2[i];
            val[k++] = r2[i];
        }
        scanf("%d",&q);
        for(int i = 1; i <= q; i ++){
    
    
            scanf("%d%d%d",&num[i].id,&num[i].l,&num[i].r);
            val[k++] = num[i].l;
            val[k++] = num[i].r;
        }
        sort(val ,val + k);
        k = unique(val,val + k) - val;
        memset(sum,0,sizeof(sum));
        for(int i = 1; i <= n; i ++){
    
    
            l1[i] = lower_bound(val,val + k,l1[i]) - val + 1;
            r1[i] = lower_bound(val,val + k,r1[i]) - val + 1;;
            update(1,l1[i],1,k,1);
            update(2,r1[i],1,k,1);
        }
        for(int i = 1; i <= m; i ++){
    
    
            l2[i] = lower_bound(val,val + k,l2[i]) - val + 1;
            r2[i] = lower_bound(val,val + k,r2[i]) - val + 1;
            update(3,l2[i],1,k,1);
            update(4,r2[i],1,k,1);
        }
        ll ans = 0;
        for(int i = 1; i <= n; i ++){
    
    
            ans += m;
            if(l1[i] != 1) ans -= query(4,1,l1[i] - 1,1,k,1);
            if(r1[i] != k) ans -= query(3,r1[i] + 1,k,1,k,1);
        }
        printf ("Case %d: %lld\n",tot++,ans);
        for(int i = 1; i <= q; i ++){
    
    
            int l = lower_bound(val,val + k,num[i].l) - val + 1;
            int r = lower_bound(val,val + k,num[i].r) - val + 1;
            if(num[i].id == 1){
    
    
               ans += m;
               if(l != 1) ans -= query(4,1,l - 1,1,k,1);
               if(r != k) ans -= query(3,r + 1,k,1,k,1);
               update(1,l,1,k,1);
               update(2,r,1,k,1);
               n++;
            }
            if(num[i].id == 2){
    
    
               ans += n;
               if(l != 1) ans -= query(2,1,l - 1,1,k,1);
               if(r != k) ans -= query(1,r + 1,k,1,k,1);
               update(3,l,1,k,1);
               update(4,r,1,k,1);
               m++;
            }
            printf ("%lld\n",ans);
        }
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/hddddh/article/details/109803011