题解 P4396 [AHOI2013]作业

https://www.luogu.com.cn/problem/P4396

一道用值域分块维护莫队的模板题。

还是用值域分块把,用树状数组会T。

不过还是贴一下树状数组的代码。

copy
#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> #define LL long long #define rint register int using namespace std; namespace FastIO { const int _SIZE = (1 << 21) + 1; char ibuf[_SIZE],obuf[_SIZE]; char *iS,*iT; char c; char qu[55]; char *oS=obuf,*oT=oS+_SIZE-1; bool _sign=false; int qr; // getchar #define gc() (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, _SIZE, stdin), (iS == iT ? EOF : *iS++)) : *iS++) // print the remaining part inline void flush() { fwrite(obuf,1,oS-obuf,stdout); oS=obuf; return; } // putchar inline void putc(const char &x) { *oS++=x; if(oS==oT) flush(); return; } inline char getc() { return gc(); } // input a signed integer template <class T> inline void read(T &x) { x=0; _sign=false; for (c=gc();c<'0'||c>'9';c=gc()) if (c=='-') _sign=true; for (;c>='0'&&c<='9';c=gc()) x=(x<<1)+(x<<3)+(c&15); x=(_sign) ? (~x+1) : x; return; } // print a signed integer template <class T> inline void print(T x) { if (!x) { putc('0'); return; } if (x<0) putc('-'),x=~x+1; while(x) qu[++qr]=x%10+'0',x/=10; while(qr) putc(qu[qr--]); return; } // no need to call flush at the end manually! struct Flusher_ { ~Flusher_() { flush(); } }io_flusher_; } // namespace io using FastIO::read; using FastIO::print; using FastIO::putc; using FastIO::getc; //================================================= const int N=1e5+5; int n,m; struct Bits { int c[N]; int res; inline int lowbit(const int &x) { return x&(-x); } inline void update(int x,int y) { for(;x<=n;x+=lowbit(x)) c[x]+=y; return; } inline int sum(int x) { res=0; for(;x>=1;x-=lowbit(x)) res+=c[x]; return res; } }C1,C2; int a[N]; int t[N]; struct quiz { int l,r; int a,b; int ans1,ans2; int o; }q[N]; int siz; inline bool cmp(const quiz &a,const quiz &b) { if(a.l/siz!=b.l/siz) return a.l<b.l; else return a.r<b.r; } inline bool rule(const quiz &a,const quiz &b) { return a.o<b.o; } inline void Add(int pos) { if(t[a[pos]]==0) C2.update(a[pos],1); C1.update(a[pos],1); ++t[a[pos]]; return; } inline void Sub(int pos) { if(t[a[pos]]==1) C2.update(a[pos],-1); C1.update(a[pos],-1); --t[a[pos]]; return; } int main() { // freopen("1.in","r",stdin); rint i; read(n); read(m); for(i=1;i<=n;i++) read(a[i]); for(i=1;i<=m;i++) { read(q[i].l); read(q[i].r); read(q[i].a); read(q[i].b); q[i].o=i; } siz=sqrt(n); sort(q+1,q+m+1,cmp); rint head=1,tail=0; for(i=1;i<=m;i++) { while(head>q[i].l) Add(--head); while(tail<q[i].r) Add(++tail); while(head<q[i].l) Sub(head++); while(tail>q[i].r) Sub(tail--); q[i].ans1=C1.sum(q[i].b)-C1.sum(q[i].a-1); q[i].ans2=C2.sum(q[i].b)-C2.sum(q[i].a-1); } sort(q+1,q+m+1,rule); for(i=1;i<=m;i++) { print(q[i].ans1); putc(' '); print(q[i].ans2); putc('\n'); } return 0; }

时间复杂度 O((m+n)nlogn+m(logn+logC) (C为值域)

o2 过的。

值域分块

copy
#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> #define LL long long #define rint register int using namespace std; namespace FastIO { const int _SIZE = (1 << 21) + 1; char ibuf[_SIZE],obuf[_SIZE]; char *iS,*iT; char c; char qu[55]; char *oS=obuf,*oT=oS+_SIZE-1; bool _sign=false; int qr; // getchar #define gc() (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, _SIZE, stdin), (iS == iT ? EOF : *iS++)) : *iS++) // print the remaining part inline void flush() { fwrite(obuf,1,oS-obuf,stdout); oS=obuf; return; } // putchar inline void putc(const char &x) { *oS++=x; if(oS==oT) flush(); return; } inline char getc() { return gc(); } // input a signed integer template <class T> inline void read(T &x) { x=0; _sign=false; for (c=gc();c<'0'||c>'9';c=gc()) if (c=='-') _sign=true; for (;c>='0'&&c<='9';c=gc()) x=(x<<1)+(x<<3)+(c&15); x=(_sign) ? (~x+1) : x; return; } // print a signed integer template <class T> inline void print(T x) { if (!x) { putc('0'); return; } if (x<0) putc('-'),x=~x+1; while(x) qu[++qr]=x%10+'0',x/=10; while(qr) putc(qu[qr--]); return; } // no need to call flush at the end manually! struct Flusher_ { ~Flusher_() { flush(); } }io_flusher_; } // namespace io using FastIO::read; using FastIO::print; using FastIO::putc; using FastIO::getc; //================================================= const int N=1e5+5; const int SQ=1e3+5; int n,m; int F[N]; int L[SQ],R[SQ]; int size,k; void Build() { size=sqrt(N); k=N/size+(N/size>0); rint i,j; for(i=1;i<=k;i++) { L[i]=R[i-1]+1; R[i]=i*size; } R[k]=N-1; for(i=1;i<=k;i++) for(j=L[i];j<=R[i];j++) F[j]=i; return; } struct Block { int num[SQ]; int t[N]; inline void insert(const int &val) { t[val]++; num[F[val]]++; return; } inline void erase(const int &val) { t[val]--; num[F[val]]--; return; } inline int count(const int &l,const int &r) { rint i,res=0; if(F[l]==F[r]) { for(i=l;i<=r;i++) res+=t[i]; return res; } for(i=l;i<=R[F[l]];i++) res+=t[i]; for(i=F[l]+1;i<=F[r]-1;i++) res+=num[i]; for(i=L[F[r]];i<=r;i++) res+=t[i]; return res; } }A,B; int a[N]; struct quiz { int l,r; int a,b; int ans1,ans2; int o; }q[N]; int siz; inline bool cmp(const quiz &a,const quiz &b) { if(a.l/siz!=b.l/siz) return a.l<b.l; else return a.r<b.r; } inline bool rule(const quiz &a,const quiz &b) { return a.o<b.o; } inline void Add(int pos) { if(A.count(a[pos],a[pos])==0) B.insert(a[pos]); A.insert(a[pos]); return; } inline void Sub(int pos) { if(A.count(a[pos],a[pos])==1) B.erase(a[pos]); A.erase(a[pos]); return; } int main() { // freopen("1.in","r",stdin); rint i; read(n); read(m); for(i=1;i<=n;i++) read(a[i]); for(i=1;i<=m;i++) { read(q[i].l); read(q[i].r); read(q[i].a); read(q[i].b); q[i].o=i; } Build(); siz=sqrt(n); sort(q+1,q+m+1,cmp); rint head=1,tail=0; for(i=1;i<=m;i++) { while(head>q[i].l) Add(--head); while(tail<q[i].r) Add(++tail); while(head<q[i].l) Sub(head++); while(tail>q[i].r) Sub(tail--); q[i].ans1=A.count(q[i].a,q[i].b); q[i].ans2=B.count(q[i].a,q[i].b); } sort(q+1,q+m+1,rule); for(i=1;i<=m;i++) { print(q[i].ans1); putc(' '); print(q[i].ans2); putc('\n'); } return 0; }

时间复杂度:O((n+m)n+mC+mlogn)

使用值域分块能达到复杂度的平衡。(指针移动 O((n+m)n),求解 O(mC)

写分块一定要记得特判最后一个块,

copy
k=N/size+(N/size>0);
copy
R[k]=N-1;

不然要么开太小了,要么越界。

posted @   cjlworld  阅读(135)  评论(0编辑  收藏  举报
编辑推荐:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起