http://acm.hdu.edu.cn/showproblem.php?pid=4638

线段树 离线处理

题意为询问一段区间里的数能组成多少段连续的数。先考虑从左往右一个数一个数添加,考虑当前添加了i - 1个数的答案是x,那么添加完i个数后的答案是多少?可以看出,是根据a[i]-1a[i]+1是否已经添加而定的,如果a[i]-1或者a[i]+1已经添加一个,则段数不变,如果都没添加则段数加1,如果都添加了则段数减1。设v[i]为加入第i个数后的改变量,那么加到第x数时的段数就是sum{v[i]} (1<=i<=x}。仔细想想,若删除某个数,那么这个数两端的数的改变量也会跟着改变,这样一段区间的数构成的段数就还是他们的v值的和。将询问离线处理,按左端点排序后扫描一遍,左边删除,右边插入,查询就是求区间和。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define mid ((t[rt].l+t[rt].r)>>1)
const int maxn = 101000;
struct node {
    int l , r , sum;
}t[maxn<<2];
void pushup(int rt) {
    t[rt].sum = t[ls].sum + t[rs].sum;
}
void build(int l,int r,int rt) {
    t[rt].sum = 0; t[rt].l = l; t[rt].r = r;
    if(l == r) return;
    build(l,mid,ls);
    build(mid+1,r,rs);
}
void update(int pos , int val , int rt) {
    if(t[rt].l == t[rt].r) {
        t[rt].sum = val;
        return;
    }
    if(pos <= mid) update(pos , val , ls);
    else update(pos , val , rs);
    pushup(rt);
}
int query(int l ,int r,int rt) {
    if(t[rt].l == l && t[rt].r == r) return t[rt].sum;
    if(l > mid) return query(l, r, rs);
    else if(r <= mid) return query(l , r , ls);
    else return query(l , mid , ls) + query(mid+1 , r , rs);
}
int n , m , T;
struct cmd {
    int l , r , id , ans;
}c[maxn];
bool cmp(cmd a , cmd b) {
    return a.l < b.l;
}
bool cmp2(cmd a , cmd b) {
    return a.id < b.id;
}
int a[maxn] , pos[maxn];
int check(int num , int L) {
    int ans = 0;
    if(num > 1 && pos[num-1] >= L && pos[num-1] < pos[num] ) ans ++;
    if(num < n && pos[num+1] >= L && pos[num+1] < pos[num] ) ans ++;
    if(ans == 1) return 0;
    else if(ans == 2) return -1;
    else return 1;
}
int main() {
    scanf("%d" , &T);
    while(T--) {
        scanf("%d%d" ,&n , &m);
        build(1 , n , 1);
        for(int i=1;i<=n;i++) {
            scanf("%d" , &a[i]);
            pos[ a[i] ] = i;
        }
        for(int i=0;i<m;i++) {
            scanf("%d%d" , &c[i].l , &c[i].r);
            c[i].id = i;
        }

        sort(c , c + m , cmp);
        for(int i=1;i<=n;i++) {
            int val = check(a[i] , 0);
            update(i , val , 1);
        }
        int le = 0;
        for(int i=0;i<m;i++) {
            for(;le<c[i].l;le++) {
                int val;
                if(a[le] < n) {
                    val = check(a[le]+1 , c[i].l);
                    update(pos[ a[le]+1 ],val,1);
                }
                if(a[le] > 1) {
                    val = check(a[le]-1 , c[i].l);
                    update(pos[ a[le]-1 ],val,1);
                }
            }
            c[i].ans = query(c[i].l , c[i].r , 1);
        }
        sort(c , c+m , cmp2);
        for(int i=0;i<m;i++) printf("%d\n" , c[i].ans);
    }
    return 0;
}

 

  

 

 posted on 2013-08-02 13:58  tobec  阅读(227)  评论(0编辑  收藏  举报