http://acm.hdu.edu.cn/showproblem.php?pid=4638
线段树 离线处理
题意为询问一段区间里的数能组成多少段连续的数。先考虑从左往右一个数一个数添加,考虑当前添加了i - 1个数的答案是x,那么添加完i个数后的答案是多少?可以看出,是根据a[i]-1和a[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; }