小 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]);
}

jzoj5848的更多相关文章

随机推荐

  1. 用java创建UDF,并用于Hive

    典型代码如下: 导入UDF类: import org.apache.hadoop.hive.ql.exec.UDF; public class UpperCassUDF extends UDF{ pu ...

  2. CSV 文件

    CSV 文件 CSV(Comma Separated Values 逗号分隔值) 是一种文件格式(如.txt..doc等),也可理解 .csv 文件就是一种特殊格式的纯文本文件.即是一组字符序列,字符 ...

  3. android的 Base64

    byte[] key=Base64.decode("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4".getBytes(), Base64.DEFAULT);   ...

  4. tomcat中如何配置虚拟路径

    第一步:打开server.xml配置文件.在Host节点里写上该行代码: <Context path="/upload" docBase="E:\upload&qu ...

  5. xampp环境 安装 用法 composer

    准备工作 1.打开PHP配置文件E:\xampp\php\php.ini确认以下模块已开启(移除前面的分号). extension=php_openssl.dll, extension=php_cur ...

  6. [GO]关于go的waitgroup

    watigroup是用来控制一组goroutine的,用来等待一组goroutine结束 比如关于kafka的消费者代码除了生硬的让程序等待一个小时,也可以这样写 package main impor ...

  7. java判断字符串是否为数字,包括负数

    /** * 判断是否为数字,包含负数情况 * @param str * @return */ private boolean isNumeric(String str){ Boolean flag = ...

  8. UVa 10269 Adventure of Super Mario (Floyd + DP + BFS)

    题意:有A个村庄,B个城市,m条边,从起点到终点,找一条最短路径.但是,有一种工具可以使人不费力的移动L个长度,但始末点必须是城市或村庄.这种工具有k个,每个只能使用一次,并且在城市内部不可使用,但在 ...

  9. GitBash入门

    转载自:http://www.cnblogs.com/randomsteps/p/5415116.html 作为一个初学者,我是跟着廖学峰老师的官方博客学习,这里只是做个笔记,哈哈,关于git的历史. ...

  10. Shiro 登录页面的几个固定字段

    http://shiro.apache.org/webapp-tutorial.html Step 3b: Add a login page Since Step 3a enabled login a ...