标签:bzoj bzoj2038 莫队算法 曼哈顿距离最小生成树 分块
题目大意:给定n个点,每个点有一个颜色,m次询问,每次询问一个区间内随机选出两个点颜色相同的概率是多少
OTZ莫队算法……
具体做法无论是分块还是曼哈顿最小生成树网上都讲解的很详细 我就不累述了
这个题的做法是记录一个cnt数组表示当前区间内每种颜色有多少个
加入一个颜色为x的点就ans+=cnt[x] 然后cnt[x]++
减少一个颜色为x的点就cnt[x]-- 然后ans-=cnt[x]
于是添加或删除一个点O(1)出解 这里拎出来解释一下 因为我代码里写的表达式太凶残了
我两个版本都写了一遍……然后这就是结果
上面是曼哈顿最小生成树,下面是分块
于是分块无论是时间上还是代码复杂度上都完爆MMST……果断分块大法好啊0.0
不过MMST写着真心高大上0.0 给人一种【哇塞我连这种高端算法都搞定了あたいは最強ね!】的错觉QAQ
总之两个版本都贴上来吧 对比一下
分块:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 50500 using namespace std; struct query{ int l,r,pos; bool operator < (const query &x) const; }q[M]; int n,m,block; int a[M],belong[M],cnt[M]; pair<unsigned int,unsigned int> ans[M]; unsigned int now; bool query :: operator < (const query &x) const { if(belong[l]==belong[x.l]) return r<x.r; return belong[l]<belong[x.l]; } int main() { #ifdef PoPoQQQ freopen("2038.in","r",stdin); freopen("2038.out","w",stdout); #endif int i; cin>>n>>m; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].pos=i; block=static_cast<int>(ceil(sqrt(n))); for(i=1;i<=n;i++) belong[i]=(i-1)/block+1; sort(q+1,q+m+1); int l=1,r=0; for(i=1;i<=m;i++) { while(r<q[i].r) now+=cnt[a[++r]]++; while(r>q[i].r) now-=--cnt[a[r--]]; while(l<q[i].l) now-=--cnt[a[l++]]; while(l>q[i].l) now+=cnt[a[--l]]++; unsigned int temp=(unsigned)(r-l+1)*(r-l)>>1; unsigned int gcd=__gcd(now,temp); ans[q[i].pos]=make_pair(now/gcd,temp/gcd); } for(i=1;i<=m;i++) printf("%u/%u\n",ans[i].first,ans[i].second); }
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 50500 using namespace std; struct edge{ int x,y,f; bool operator < (const edge &z) const { return f < z.f; } }e[M<<2]; struct point{ int x,y,pos,key; bool operator < (const point &p) const { if(x==p.x) return y>p.y; return x>p.x; } }points[M]; struct query{ int l,r; }q[M]; struct abcd{ int to,next; }table[M<<1]; int head[M],tot; int n,m,k,a[M],c[M]; int fa[M]; int l=1,r=0,cnt[M]; unsigned int now; pair<unsigned int,unsigned int>ans[M]; int Find(int x) { if(!fa[x]||fa[x]==x) return fa[x]=x; return fa[x]=Find(fa[x]); } void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void Update(int x,int y) { for(;x;x-=x&-x) if(points[y].x+points[y].y<points[c[x]].x+points[c[x]].y) c[x]=y; } int Get_Ans(int x) { int re=0; for(;x<=m;x+=x&-x) if(points[c[x]].x+points[c[x]].y<points[re].x+points[re].y) re=c[x]; return re; } void Calculate() { int i,temp=0; static pair<int,int>b[M]; for(i=1;i<=m;i++) b[i]=make_pair(points[i].y-points[i].x,i); sort(b+1,b+m+1); for(i=1;i<=m;i++) { if(i==1||b[i].first!=b[i-1].first) ++temp; points[b[i].second].key=temp; } sort(points+1,points+m+1); memset(c,0,sizeof c); for(i=1;i<=m;i++) { temp=Get_Ans(points[i].key); if(temp) { e[++k].f=points[temp].x+points[temp].y-points[i].x-points[i].y; e[k].x=points[i].pos;e[k].y=points[temp].pos; } Update(points[i].key,i); } } void Kruskal() { int i; sort(e+1,e+k+1); for(i=1;i<=k;i++) { int x=e[i].x,y=e[i].y; if(Find(x)!=Find(y)) { fa[Find(x)]=Find(y); Add(x,y),Add(y,x); } } } void DFS(int x,int from) { int i; while(r<q[x].r) now+=cnt[a[++r]]++; while(l>q[x].l) now+=cnt[a[--l]]++; while(r>q[x].r) now-=--cnt[a[r--]]; while(l<q[x].l) now-=--cnt[a[l++]]; unsigned int temp=(unsigned)(r-l+1)*(r-l)>>1; unsigned int gcd=__gcd(now,temp); ans[x]=make_pair(now/gcd,temp/gcd); for(i=head[x];i;i=table[i].next) { if(table[i].to==from) continue; DFS(table[i].to,x); while(r<q[x].r) now+=cnt[a[++r]]++; while(l>q[x].l) now+=cnt[a[--l]]++; while(r>q[x].r) now-=--cnt[a[r--]]; while(l<q[x].l) now-=--cnt[a[l++]]; } } int main() { #ifdef PoPoQQQ freopen("2038.in","r",stdin); freopen("2038.out","w",stdout); #endif int i; cin>>n>>m; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) { scanf("%d%d",&q[i].l,&q[i].r); points[i].x=q[i].l; points[i].y=q[i].r; points[i].pos=i; } points[0].x=points[0].y=0x3f3f3f3f; Calculate(); for(i=1;i<=m;i++) points[i].y=-points[i].y; Calculate(); for(i=1;i<=m;i++) points[i].y=-points[i].y,swap(points[i].x,points[i].y); Calculate(); for(i=1;i<=m;i++) points[i].y=-points[i].y; Calculate(); Kruskal(); DFS(1,0); for(i=1;i<=m;i++) printf("%u/%u\n",ans[i].first,ans[i].second); }
BZOJ 2038 2009国家集训队 小Z的袜子(hose) 莫队算法
标签:bzoj bzoj2038 莫队算法 曼哈顿距离最小生成树 分块
原文地址:http://blog.csdn.net/popoqqq/article/details/40889549