HDU 4638 Group

来源:互联网 发布:购物软件需求分析报告 编辑:程序博客网 时间:2024/06/01 19:37

主要借鉴这一篇:http://www.2cto.com/kf/201308/233187.html

思路:如果我们从左到右一个个加进来,那么对于加进来的第i个数num[i],那么它就能增加一个段(num[i]+1,和num[i]-1在之前都没出现过),或者减少一个段(num[i]+1,和num[i]-1在之前都出现过),或者不增不减(num[i]+1,和num[i]-1在之前只出现过其中一个)。那么我们要找的询问的区间[l,r]内有多少个区间,就是询问[l,r]内的数,增加了几个这样的段。但是直接询问[l,r]内的数产生的段数是不可以的,因为对于[l,r]内的某一个数,有可能它所能产生的段数是跟l之前,或者r之后的数有关的。因此我们可以将询问离线出来,按r排好序,每次询问之前,将r之前的数产生的影响先清除掉,也就是对于某个在r之前的数,将它所能影响的后面的数能增加的段去除,对于之前的已经不用管了,因为我们按右端点排序,所以在清除某一个数时,它前面的数的影响之前已经处理掉了。所以这个区间的段数自然就是[l,r]的区间和。

线段树和树状数组都能做,这里附上两份代码:

线段树:

#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <map>#include <vector>#include <cmath>#include <stack>#include <queue>#include <cstdlib>#include <algorithm>using namespace std;typedef __int64 int64;typedef long long ll;#define M 100005#define mod 1000000007struct node{int l , r , val;}tree[M*4] , tp[M];int num[M] , pos[M] , ans[M];bool vis[M];bool cmp(node a , node b){if (a.r < b.r)return true;return false;}void Build(int l , int r , int rt){tree[rt].l = l;tree[rt].r = r;tree[rt].val = 0;if (l == r)return;int mid = (l+r)>>1;Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);}void Updata(int rt , int pos , int val){int l = tree[rt].l;int r = tree[rt].r;tree[rt].val += val;if (l == r)return;int mid = (l+r)>>1;if (pos <= mid)Updata(rt<<1,pos,val);else Updata(rt<<1|1,pos,val);}int Query(int rt , int l , int r){if (l == tree[rt].l && r == tree[rt].r)return tree[rt].val;int mid = (tree[rt].l+tree[rt].r)>>1;if (r <= mid)return Query(rt<<1,l,r);if (l > mid)return Query(rt<<1|1,l,r);return Query(rt<<1,l,mid)+Query(rt<<1|1,mid+1,r);}int main(){int n , m , i , t;scanf("%d",&t);while (t--){scanf("%d%d",&n,&m);memset(vis , 0 , sizeof vis);for (i = 1 ; i <= n ; i++){scanf("%d",num+i);pos[num[i]] = i;}for (i = 1 ; i <= m ; i++){scanf("%d%d",&tp[i].l,&tp[i].r);tp[i].val = i;}sort(tp+1 , tp+m+1 , cmp);Build(1,n,1);int cnt = 1;ans[1] = ans[2] = -5;for (i = 1 ; i <= n ; i++){Updata(1,i,1);vis[num[i]] = 1;if (vis[num[i]+1])Updata(1,pos[num[i]+1],-1);if (vis[num[i]-1])Updata(1,pos[num[i]-1],-1);while (i == tp[cnt].r && cnt <= m){ans[tp[cnt].val] = Query(1,tp[cnt].l,tp[cnt].r);cnt++;}}for (i = 1 ; i <= m ; i++)printf("%d\n",ans[i]);}return 0;}

 

树状数组:

#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <map>#include <vector>#include <cmath>#include <stack>#include <queue>#include <cstdlib>#include <algorithm>using namespace std;typedef __int64 int64;typedef long long ll;#define M 100005#define mod 1000000007struct node{int l , r , val;}tp[M];int n , m , num[M] , pos[M] , ans[M] , sum[M];bool vis[M];bool cmp(node a , node b){if (a.r < b.r)return true;return false;}int Lowbit(int x){return x&(-x);}void Updata(int pos , int val){while (pos <= n){sum[pos] += val;pos += Lowbit(pos);}}int Query(int l , int r){int ret = 0;while (r > 0){ret += sum[r];r -= Lowbit(r);}l--;while (l > 0){ret -= sum[l];l -= Lowbit(l);}return ret;}int main(){int i , t;scanf("%d",&t);while (t--){scanf("%d%d",&n,&m);memset(vis , 0 , sizeof vis);memset(sum , 0 , sizeof sum);for (i = 1 ; i <= n ; i++){scanf("%d",num+i);pos[num[i]] = i;}for (i = 1 ; i <= m ; i++){scanf("%d%d",&tp[i].l,&tp[i].r);tp[i].val = i;}sort(tp+1 , tp+m+1 , cmp);int cnt = 1;for (i = 1 ; i <= n ; i++){Updata(i,1);vis[num[i]] = 1;if (vis[num[i]+1])Updata(pos[num[i]+1],-1);if (vis[num[i]-1])Updata(pos[num[i]-1],-1);while (i == tp[cnt].r && cnt <= m){ans[tp[cnt].val] = Query(tp[cnt].l,tp[cnt].r);cnt++;}}for (i = 1 ; i <= m ; i++)printf("%d\n",ans[i]);}return 0;}