C35 线段树+排序 P1972 [SDOI2009] HH的项链
视频链接:C35 线段树+排序 P1972 [SDOI2009] HH的项链_哔哩哔哩_bilibili
// 线段树+排序 #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define N 1000005 #define ls u<<1 #define rs u<<1|1 int n,m; struct tree{ int l,r,sum; }tr[N*4]; //线段树 struct node{ int l,r,id; bool operator<(node &b){ return r<b.r; } }q[N]; //查询 vector<int> v[N]; //右端点相同的查询 int a[N],last[N],ans[N]; void pushup(int u){ //上传 tr[u].sum=tr[ls].sum+tr[rs].sum; } void build(int u,int l,int r){ //建树 tr[u]={l,r,1}; if(l==r) return; int m=l+r>>1; build(ls,l,m); build(rs,m+1,r); pushup(u); } void change(int u,int x){ //点修 if(tr[u].l==x&&tr[u].r==x){ tr[u].sum=0; return; } int m=tr[u].l+tr[u].r>>1; if(x<=m) change(ls,x); else change(rs,x); pushup(u); } int query(int u,int x,int y){ //区查 if(x>tr[u].r || y<tr[u].l) return 0; if(x<=tr[u].l&&tr[u].r<=y) return tr[u].sum; return query(ls,x,y)+query(rs,x,y); } // int query(int u,int x,int y){ //区查 // if(x<=tr[u].l&&tr[u].r<=y) return tr[u].sum; // int m=tr[u].l+tr[u].r>>1; // if(y<=m) return query(ls,x,y); // if(x>m) return query(rs,x,y); // return query(ls,x,m)+query(rs,m+1,y); // } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; //每个查询的编号 } sort(q+1,q+m+1); //按查询右端点排序 for(int i=1;i<=m;i++) v[q[i].r].push_back(i); //右端点相同的查询 build(1,1,n); for(int i=1;i<=n;i++){ //枚举每个数 if(last[a[i]]) change(1,last[a[i]]); last[a[i]]=i; //记录ai最后一次的下标 for(auto t : v[i]) //处理右端点i的查询 ans[q[t].id]=query(1,q[t].l,q[t].r); } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }