BZOJ3236: [Ahoi2013]作业
Description
Input
Output
Sample Input
3 4
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3
Sample Output
2 2
1 1
3 2
2 1
1 1
3 2
2 1
HINT
N=100000,M=1000000
对权值建立线段树,对应询问在权值区间内打上标记,那么最后对线段树上的每个节点,问题就转化成HH的项链了。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } const int maxn=100010; const int maxm=1000010; const int maxnode=20000010; int n,m,first[maxn],next[maxn],to[maxn],cnt; void AddVal(int u,int v) { next[++cnt]=first[u];to[cnt]=v;first[u]=cnt; } int L[maxm],R[maxm],ans[maxm],ans2[maxm],first2[maxn*3],next2[maxnode],to2[maxnode],ToT; void AddQuery(int u,int v) { next2[++ToT]=first2[u];to2[ToT]=v;first2[u]=ToT; } void query(int o,int l,int r,int ql,int qr,int val) { if(ql<=l&&r<=qr) AddQuery(o,val); else { int mid=l+r>>1,lc=o<<1,rc=lc|1; if(ql<=mid) query(lc,l,mid,ql,qr,val); if(qr>mid) query(rc,mid+1,r,ql,qr,val); } } struct Solver { int x,v,t; bool operator < (const Solver& ths) const { return x<ths.x; } }A[maxn],B[maxm]; int sumv[maxn],clo[maxn],nxt[maxn],clo2[maxn],lst[maxn],T,T2; void add(int x,int v) { if(x>n) return; for(;x<=n;x+=x&-x) { if(clo[x]==T) sumv[x]+=v; else clo[x]=T,sumv[x]=v; } } int sum(int x) { int res=0; for(;x;x-=x&-x) if(clo[x]==T) res+=sumv[x]; return res; } void solve(int o,int l,int r) { if(l!=r) { int mid=l+r>>1,lc=o<<1,rc=lc|1; solve(lc,l,mid);solve(rc,mid+1,r); } int m1=0,m2=0; rep(x,l,r) ren A[++m1]=(Solver){to[i],x,0}; if(!m1||!first2[o]) return; T++; rep(i,1,m1) add(A[i].x,1); for(int i=first2[o];i;i=next2[i]) ans[to2[i]]+=sum(R[to2[i]])-sum(L[to2[i]]-1); T++;T2++; for(int i=first2[o];i;i=next2[i]) B[++m2]=(Solver){L[to2[i]],R[to2[i]],to2[i]}; sort(A+1,A+m1+1);sort(B+1,B+m2+1); dwn(i,m1,1) { if(clo2[A[i].v]!=T2) clo2[A[i].v]=T2,lst[A[i].v]=i,nxt[i]=m1+1; else nxt[i]=lst[A[i].v],lst[A[i].v]=i; }T2++; rep(i,1,m1) if(clo2[A[i].v]!=T2) { clo2[A[i].v]=T2; add(A[i].x,1); } int j=1; rep(i,1,m2) { while(j<=m1&&A[j].x<B[i].x) { add(A[j].x,-1); if(nxt[j]<=m1) add(A[nxt[j]].x,1); j++; } ans2[B[i].t]+=sum(B[i].v)-sum(B[i].x-1); } } int main() { n=read();m=read(); rep(i,1,n) AddVal(read(),i); rep(i,1,m) { L[i]=read();R[i]=read(); int a=read(),b=read(); query(1,1,n,a,b,i); } solve(1,1,n); rep(i,1,m) printf("%d %d\n",ans[i],ans2[i]); return 0; }
莫队大法也很资瓷啊。对权值分块以牺牲询问复杂度的代价来降低修改复杂度。
不知道为什么O(Msqrt(N))的做法比O(Mlog^2N)的做法快了3倍。。。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } const int maxn=100010; const int maxm=1000010; int n,m,A[maxn],blo[maxn],st[maxn],en[maxn]; struct Query { int l,r,a,b,id; bool operator < (const Query& ths) const { if(blo[l]==blo[ths.l]) return r<ths.r; return l<ths.l; } }Q[maxm]; int ans[maxm],ans2[maxm],cnt[maxn],sum[maxn],bloans[maxn]; void add(int x) { if(!cnt[x]) bloans[blo[x]]++; cnt[x]++;sum[blo[x]]++; } void del(int x) { cnt[x]--;sum[blo[x]]--; if(!cnt[x]) bloans[blo[x]]--; } void query(int x,int l,int r) { rep(i,blo[l]+1,blo[r]-1) ans2[x]+=bloans[i],ans[x]+=sum[i]; if(blo[l]==blo[r]) rep(i,l,r) ans2[x]+=(cnt[i]>0),ans[x]+=cnt[i]; else { rep(i,l,en[blo[l]]) ans2[x]+=(cnt[i]>0),ans[x]+=cnt[i]; rep(i,st[blo[r]],r) ans2[x]+=(cnt[i]>0),ans[x]+=cnt[i]; } } int main() { n=read();m=read();int SIZE=(int)sqrt(n); rep(i,1,n) { A[i]=read();blo[i]=(i-1)/SIZE+1; if(!st[blo[i]]) st[blo[i]]=i; en[blo[i]]=i; } rep(i,1,m) Q[i].l=read(),Q[i].r=read(),Q[i].a=read(),Q[i].b=read(),Q[i].id=i; sort(Q+1,Q+m+1); int l=1,r=0; rep(i,1,m) { while(l>Q[i].l) add(A[--l]); while(r<Q[i].r) add(A[++r]); while(l<Q[i].l) del(A[l++]); while(r>Q[i].r) del(A[r--]); query(Q[i].id,Q[i].a,Q[i].b); } rep(i,1,m) printf("%d %d\n",ans[i],ans2[i]); return 0; }