1. 程式人生 > >BZOJ3809: Gty的二逼妹子序列

BZOJ3809: Gty的二逼妹子序列

main sum 在線 for http 樹狀數組 LG del 不能

【傳送門:BZOJ3809


簡要題意:

  給出一個n個數的序列,序列中的數範圍為1到n,給出m個操作,每個操作輸入l,r,a,b,輸出l到r中權值為a到b的數的種類


題解:

  肯定不能在線求,離線就用莫隊

  一開始想法是用樹狀數組維護權值總類,結果T了

  旁邊的lxj大佬D了我,說:這道題卡了樹狀數組,因為它修改帶log

  認真地聽了一波講解,就直接把權值也給分塊了

  因為權值和數的個數的區間是一樣的,所以可以一並分塊

  然後修改O(1),而求值用n0.5,直接卡了過去

  伏地膜lxj大佬


參考代碼:

#include<cstdio>
#include
<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int l,r,a,b,id,d; }q[1100000]; int s[110000]; int bl[1100],br[1100],belong[110000]; bool cmp1(node n1,node n2) { if(belong[n1.l]<belong[n2.l]) return true; if(belong[n1.l]>belong[n2.l]) return
false; if(belong[n1.l]==belong[n2.l]) { if(n1.r<n2.r) return true; if(n1.r>n2.r) return false; } return false; } bool cmp2(node n1,node n2) { return n1.id<n2.id; } int d[1100],sum[110000]; void add(int x) { sum[x]++; if(sum[x]==1) d[belong[x]]++; }
void del(int x) { sum[x]--; if(sum[x]==0) d[belong[x]]--; } int solve(int x,int y) { int bx=belong[x],by=belong[y]; int ans=0; if(bx==by) { for(int i=x;i<=y;i++) { if(sum[i]>0) ans++; } return ans; } for(int i=bx+1;i<=by-1;i++) ans+=d[i]; for(int i=x;i<=br[bx];i++) if(sum[i]>0) ans++; for(int i=bl[by];i<=y;i++) if(sum[i]>0) ans++; return ans; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&s[i]); int block=int(sqrt(n)); for(int i=1;i<=n;i++) { int t=(i-1)/block+1; belong[i]=t; if(bl[t]==0) br[t-1]=i-1,bl[t]=i; } br[belong[n]]=n; for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b); q[i].id=i; } sort(q+1,q+m+1,cmp1); memset(sum,0,sizeof(sum)); memset(d,0,sizeof(d)); int l=1,r=0; for(int i=1;i<=m;i++) { while(l>q[i].l){l--;add(s[l]);} while(l<q[i].l){del(s[l]);l++;} while(r>q[i].r){del(s[r]);r--;} while(r<q[i].r){r++;add(s[r]);} q[i].d=solve(q[i].a,q[i].b); } sort(q+1,q+m+1,cmp2); for(int i=1;i<=m;i++) printf("%d\n",q[i].d); return 0; }

BZOJ3809: Gty的二逼妹子序列