牛客网多校联合训练1 J Different Integers(可持久化线段树/莫队)
题意:给你一个L,R区间,让你求1-L和R-n中有多少个数
思路:最美不过夕阳红,一直没想到拼接起来,之前想到拼接,但想的是每次都进行拼接,所以是一个n2lg的操作,最后想到了拼接全部,然后就是一个经典的求区间有几个数的问题,然后果断主席树搞了一发,T50%,然后写一发莫队,同T50%,心态爆炸。校内讲题的时候,有人告诉我莫队加输入挂可以过,加了读入挂,果断过,然后又有人说,改变分块大小也可以过,改了大小以后也过了,然后看了其他人的主席树,发现只是在最后加了一下对于LR的判断,改了以后也Al ,还是没想到啊。
下面附上主席树和莫队的代码:
莫队
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include<bits/stdc++.h> using namespace std; const int N=3e5+7; int block,cnt[1000007],a[N],res[N],ans; struct node{ int l,r,id; }q[N]; bool cmp(node a,node b) { return a.l/block!=b.l/block?a.l/block<b.l/block:a.r<b.r; } void update(int p,int val) { cnt[a[p]]+=val; if(cnt[a[p]]==1&&val==1)ans++; if(cnt[a[p]]==0&&val==-1)ans--; // printf("fuck %d %d %d\n",cnt[a[p]],ans,val); } //int main() //{ // // return 0; //} int main() { int n,m; while(~scanf("%d%d",&n,&m)){ block=1000; memset(cnt,0,sizeof(cnt)); memset(res,0,sizeof(res)); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i+n]=a[i]; } for(int i=1;i<=m;i++){ int A,B; scanf("%d%d",&A,&B); q[i].l=B;q[i].r=A+n; // printf("test %d %d\n",q[i].l,q[i].r); q[i].id=i; } n*=2; sort(q+1,q+1+m,cmp); ans=0; // printf("test\n"); for(int i=1,l=1,r=0;i<=m;i++){ for(;r<q[i].r;r++) update(r+1,1); for(;r>q[i].r;r--) update(r,-1); for(;l<q[i].l;l++) update(l,-1); for(;l>q[i].l;l--) update(l-1,1); // printf("test %d %d ans === %d\n",q[i].l,q[i].r,ans); res[q[i].id]=ans; } for(int i=1;i<=m;i++){ printf("%d\n",res[i]); } } }
主席树
#include <bits/stdc++.h> using namespace std; #define met(a,b) memset(a,b,sizeof a) const int N=2e5+50; struct node { int lson,rson; int cnt; }; node T[N*40]; int root[N],tot; int sa[N]; int arr[N]; int last_pos[N]; inline void init() { met(root,0);met(last_pos,0); tot=0; T[0].cnt=T[0].lson=T[0].rson=0; } inline void update(int &cur,int ori,int l,int r,int pos,int flag) { cur=++tot; T[cur]=T[ori]; T[cur].cnt+=flag; if(l==r) return ; int mid=(l+r)/2; if(pos<=mid) update(T[cur].lson,T[ori].lson,l,mid,pos,flag); else update(T[cur].rson,T[ori].rson,mid+1,r,pos,flag); } inline int query(int S,int E,int l,int r,int x,int y) { if(x<=l&&r<=y) return T[E].cnt-T[S].cnt; else { int mid=(l+r)>>1; if(y<=mid) return query(T[S].lson,T[E].lson,l,mid,x,y); else if(x>mid) return query(T[S].rson,T[E].rson,mid+1,r,x,y); else return query(T[S].lson,T[E].lson,l,mid,x,mid)+query(T[S].rson,T[E].rson,mid+1,r,mid+1,y); } } int main() { int n,q; while(~scanf("%d%d",&n,&q)){ init(); vector<int>pos; for(int i=1; i<=n; ++i) { scanf("%d",&arr[i]); arr[i+n]=arr[i]; pos.push_back(arr[i]); // sa[i]=arr[i];sa[i+n]=arr[i+n]; } n*=2; // printf("test %d\n",n); sort(pos.begin(),pos.end()); pos.erase(unique(pos.begin(),pos.end()),pos.end()); int temp_rt=0; for(int i=1;i<=n;++i){ arr[i]=lower_bound(pos.begin(),pos.end(),arr[i])-pos.begin()+1; // arr[i]=getid(arr[i]); // printf("test %d\n",last_pos[arr[i]]); if(!last_pos[arr[i]]) { update(root[i],root[i-1],1,n,i,1); last_pos[arr[i]]=i; } else{ update(temp_rt,root[i-1],1,n,last_pos[arr[i]],-1); update(root[i],temp_rt,1,n,i,1); // update(root[i],root[i-1],1,n,i,1); last_pos[arr[i]]=i; } } while(q--){ int A,B; scanf("%d%d",&A,&B); if(A<B){ int l=B,r=A+n/2; printf("%d\n",query(root[l-1],root[r],1,n,l,r)); } else{ printf("%d\n",query(root[0],root[n],1,n,1,n)); } // printf("test sum:%d l1:%d l2:%d r-1==%d l-1==%d l==%d r==%d\n",sum,l1,l2,query(1,r-1),query(1,l-1),query(l,n),query(r,n)); // printf("%d\n",ans); } } return 0; }