小 S 热爱大自然, 一天他种了一棵奇怪的线段树.

奇怪的线段树是一种与普通线段树类似的结构, 唯一不同的是, 它不一定以每一个区间的中点作为分治中心.

麻烦的是, 小 S 的线段树被风吹散了, 散成了一个个表示单一区间的结点, 而且正在逐渐飘远. 不过小 S 早有准备, 他可以进行抓取操作, 每一次他可以给出一个抓取区间, 由于这个抓取区间只有两个端点有磁力, 所以只能抓取满足与抓取区间有交而不被抓取区间包含的所有线段树结点.

现在小 S 进行了若干次抓取操作, 对于每次操作, 他希望你能回答他一共抓取了多少个线段树结点.

這道題給出了m個區間,要求我們求構造出來的樹之中,與當前區間有交集關係而且當前區間不包含的區間到底有多少個

首先是建樹問題,我們可以按照題意遞歸建樹,看一下現在的l是否==r,不然return,否則輸入當前區間的mid,並且遞歸左子樹和右子樹,所有區間可以使用一個結構體來存下來

然後再將詢問和線段樹區間按照右端點排序

而且,這道題有區間關係,應該想到掃描線

但是,在這道題中,如果直接求出答案,會很複雜,需要很多分類討論,正難則反,所以我們可以求出與當前詢問區間不相交的區間個數

這種類型有3個:

1.該區間右端點在當前區間左端點的左邊

2.該區間被現在的區間包含

3.該區間左端點在當前區間右端點的右邊

將這些算出來以後,所有區間個數-1類個數-2類-3類個數就是當前詢問區間個數的答案

對於1:我們可以維護一個樹狀數組,其維護了當前位置合法區間右端點的前綴和。每次移動一個區間時,不斷的將下一個線段樹區間加入樹狀數組,直到下一個區間的左端點在該區間裡面。然後,查詢當前區間左端點左邊有多少個右端點,就知道了與當前區間不相交的線段個數,這樣得到了ans1

對於2:可以再維護一個樹狀數組,初始,其將所有線段樹區間的右端點都加了進去。每一次移動區間時,不斷的將下一個線段樹區間從數組刪除,知道下一個區間的左端點在該區間裡面,則我們已經去除了所有l不在這個區間的線段。現在當前的所有區間的l值都大於現在查詢區間的l值,但是我們還想要現在查詢的右端點大於當前所有區間的右端點,所以得查詢一下有多少個右端點在區間l-r中

對於3,也可以再使用一個樹狀數組維護,但是我們發現,只要維護一個後綴和,記錄有多少個區間的l值大於等於現在的l值即可,因為如果有區間的l值大於現在查詢區間的r值,則這個區間的r值一定大於查詢區間的r值。

所以我們減去即可,所有查詢區間要存id表示它是第幾個詢問

#include<bits/stdc++.h>
using namespace std;
int n,m,b[300010],c[300010],s[300010],ans[3000010];
struct no{
    int l,r,id;
    bool operator <(const no &rhs)const{
        return l<rhs.l;
    }
}x[3000010],y[3000010];
int ct=0;
void get(int l,int r){
    if(l==r)return;
    x[++ct]=(no){l,r,0};
    int mid;
    scanf("%d",&mid);
    get(l,mid);get(mid+1,r);
}
void mod1(int x,int y){for(int i=x;i<=n;i+=(i&-i))b[i]+=y;}
void mod2(int x,int y){for(int i=x;i<=n;i+=(i&-i))c[i]+=y;}
int q1(int x){
    int ans=0;
    while(x){
        ans+=b[x];
        x-=x&-x;
    }
    return ans;
}
int q2(int x){
    int ans=0;
    while(x){
        ans+=c[x];
        x-=x&-x;
    }
    return ans;
}
int main(){
    freopen("strange.in","r",stdin);
    freopen("strange.out","w",stdout);
    scanf("%d%d",&n,&m);
    get(1,n);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&y[i].l,&y[i].r);
        y[i].id=i;
    }
    sort(x+1,x+ct+1);
    sort(y+1,y+m+1);
    for(int i=1;i<=ct;i++){
        s[x[i].l]++;
        mod2(x[i].r,1);
    }
    for(int i=n;i>=1;i--)
        s[i]=s[i]+s[i+1];
    int now=1;
    for(int i=1;i<=m;i++){
        while(now<=ct&&x[now].l<y[i].l){
            mod2(x[now].r,-1);
            mod1(x[now].r,1);
            now++;
        }
        ans[y[i].id]=ct-q1(y[i].l-1)-q2(y[i].r)+q2(y[i].l-1)-s[y[i].r+1];
    }
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
}

05-11 16:14