标签:
题意:
给n个编号,m个查询每个查询l,r,求下标区间[l,r]中能分成标号连续的组数(一组内的标号是连续的)
分析:
我们认为初始,每个标号为一个组(线段树维护区间组数),从左向右扫序列,当前标号,要考虑和他相邻的标号的位置,若前面位置出现了和它相邻的标号,
则前面位置组数减一(因为可以合并成一组),查询区间离线处理,保证了查询的正确。
#include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <string> #include <cctype> #include <complex> #include <cassert> #include <utility> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef pair<int,int> PII; typedef long long ll; #define lson l,m,rt<<1 #define pi acos(-1.0) #define rson m+1,r,rt<<1|1 #define All 1,N,1 #define N 100010 #define read freopen("in.txt", "r", stdin) const ll INFll = 0x3f3f3f3f3f3f3f3fLL; const int INF= 0x7ffffff; const int mod = 1000000007; //pos 相邻标号在前面出现的位置 int sum[N*4],n,pos[N],e,a[N],tmp[N]; struct que{ int l,r,id; }q[N]; bool cmp(que x,que y){ return x.r<y.r; } void pushup(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt){ if(l==r){ sum[rt]=1; return; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt); } void update(int p,int v,int l,int r,int rt){ if(l==r){ sum[rt]+=v; return; } int m=(l+r)>>1; if(p<=m)update(p,v,lson); else update(p,v,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt){ if(L<=l&&R>=r){ return sum[rt]; } int m=(l+r)>>1; int num=0; if(L<=m)num+=query(L,R,lson); if(R>m)num+=query(L,R,rson); return num; } void solve(){ sort(q+1,q+e+1,cmp); memset(pos,0,sizeof(pos)); build(1,n,1); int b=1; for(int i=1;i<=n;++i){ if(pos[a[i]-1]) update(pos[a[i]-1],-1,1,n,1); if(pos[a[i]+1]) update(pos[a[i]+1],-1,1,n,1); pos[a[i]]=i; while(b<=e&&q[b].r==i){ tmp[q[b].id]=query(q[b].l,q[b].r,1,n,1); b++; } } for(int i=1;i<=e;++i) printf("%d\n",tmp[i]); } int main() { int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&e); for(int i=1;i<=n;++i) scanf("%d",&a[i]); for(int i=1;i<=e;++i){ scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; } solve(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/zsf123/p/4734986.html