学习了一下很基本的分块和莫队算法,因为不太会写曼哈顿距离最小生成树,所以就写了个分块版本的(分四种情况,大概这个意思吧)。。。
cogs1775||bzoj2038 小Z的袜子
题目大意:静态区间查询不同种元素的个数。
思路:用莫队扫一下,然后分子分母同时乘2,就会发现,分母是组合数化简后的(r-l)*(r-l+1),分子是每种颜色个数的平方-区间元素(从相同颜色的当中选两个可重的,去掉两个是一个的),然后就很好处理了。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; struct use{ long long zi,mu; }ans[50001]={0}; struct used{ int p,ll,rr; }ask[50001]={0}; int a[50001]={0},num[50001]={0},len; int my_comp(const used &x,const used &y) { if (x.ll/len<y.ll/len) return 1; if (x.ll/len==y.ll/len&&x.rr<=y.rr) return 1; return 0; } long long gcd(long long x,long long y) { if (x%y==0) return y; else return gcd(y,x%y); } int main() { freopen("hose.in","r",stdin); freopen("hose.out","w",stdout); int n,m,i,j,block,l,r; long long sum; scanf("%d%d",&n,&m); len=floor(sqrt(n)); for (i=1;i<=n;++i) scanf("%d",&a[i]); for (i=1;i<=m;++i) { ask[i].p=i; scanf("%d%d",&ask[i].ll,&ask[i].rr); } sort(ask+1,ask+m+1,my_comp); l=1;r=0;sum=0; for (i=1;i<=m;++i) { while(r<ask[i].rr) { ++r;sum-=(long long)num[a[r]]*num[a[r]]; ++num[a[r]];sum+=(long long)num[a[r]]*num[a[r]]; } while(r>ask[i].rr) { sum-=(long long)num[a[r]]*num[a[r]];--num[a[r]]; sum+=(long long)num[a[r]]*num[a[r]];--r; } while(l<ask[i].ll) { sum-=(long long)num[a[l]]*num[a[l]];--num[a[l]]; sum+=(long long)num[a[l]]*num[a[l]];++l; } while(l>ask[i].ll) { --l;sum-=(long long)num[a[l]]*num[a[l]]; ++num[a[l]];sum+=(long long)num[a[l]]*num[a[l]]; } ans[ask[i].p].zi=sum-(ask[i].rr-ask[i].ll+1); ans[ask[i].p].mu=(long long)(ask[i].rr-ask[i].ll+1)*(ask[i].rr-ask[i].ll); } for (i=1;i<=m;++i) { if (ans[i].zi!=0) { sum=gcd(ans[i].zi,ans[i].mu); printf("%lld/%lld\n",ans[i].zi/sum,ans[i].mu/sum); } else printf("0/1\n"); } fclose(stdin); fclose(stdout); }
cogs1822||bzoj3236 作业
题目大意:静态查询区间内数字∈[a,b]的个数和数字的种数。
思路:同上,用权值树状数组维护一下就可以了。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; struct use{ int ll,rr,aa,b,p,kk; }ask[1000001]={0}; int c1[100001]={0},c2[100001]={0},n,a[100001],len,ans[1000001][2]={0},visit[100001]={0}; int lowbit(int x) {return x&(-x);} int my_comp(const use &x,const use &y) { if (x.kk<y.kk) return 1; if (x.kk==y.kk&&x.rr<y.rr) return 1; return 0; } int bit_ask(int kind,int l,int r) { int sum=0; --l; if (kind==1) { for (;r;r-=lowbit(r)) sum+=c1[r]; for (;l;l-=lowbit(l)) sum-=c1[l]; } else { for (;r;r-=lowbit(r)) sum+=c2[r]; for (;l;l-=lowbit(l)) sum-=c2[l]; } return sum; } void bit_ins(int x) { int t;t=x; for (;t<=n;t+=lowbit(t)) c1[t]+=1; if (!visit[x]) for (;x<=n;x+=lowbit(x)) c2[x]+=1; } void bit_del(int x) { int t;t=x; for (;t<=n;t+=lowbit(t)) c1[t]-=1; if (!visit[x]) for (;x<=n;x+=lowbit(x)) c2[x]-=1; } int main() { freopen("ahoi2013_homework.in","r",stdin); freopen("ahoi2013_homework.out","w",stdout); int m,i,j,l,r; scanf("%d%d",&n,&m); len=floor(sqrt(n)); for (i=1;i<=n;++i) scanf("%d",&a[i]); for (i=1;i<=m;++i) { ask[i].p=i; scanf("%d%d%d%d",&ask[i].ll,&ask[i].rr,&ask[i].aa,&ask[i].b); ask[i].kk=ask[i].ll/len+1; } sort(ask+1,ask+m+1,my_comp); l=1;r=0; for (i=1;i<=m;++i) { while(r<ask[i].rr) { ++r;bit_ins(a[r]);++visit[a[r]]; } while(r>ask[i].rr) { --visit[a[r]];bit_del(a[r]);--r; } while(l<ask[i].ll) { --visit[a[l]];bit_del(a[l]);++l; } while(l>ask[i].ll) { --l;bit_ins(a[l]);++visit[a[l]]; } ans[ask[i].p][0]=bit_ask(1,ask[i].aa,ask[i].b); ans[ask[i].p][1]=bit_ask(2,ask[i].aa,ask[i].b); } for (i=1;i<=m;++i) printf("%d %d\n",ans[i][0],ans[i][1]); fclose(stdin); fclose(stdout); }
cogs1689||bzoj2002 Bounce 弹飞绵羊
题目大意:有n个弹力装置,每一个装置有一个值,能想后弹射k个单位(即从i弹到i+k的位置);两种操作:1是询问从i到弹飞用多少步,2是修改某个弹力装置的值。
思路:分块之后,对于每个点都保存从这个点到弹出这个块的次数,以及弹出后到的点,查询的时候√n,修改的时候只改一个块的一部分,所以也是√n。O(m√n)本来认为过不了的,没想到数据水,就这样吧。。。
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int a[200001]={0},ku[500][2]={0},kuai[500][500]={0},f[200001][2]={0}; int main() { freopen("bzoj_2002.in","r",stdin); freopen("bzoj_2002.out","w",stdout); int i,j,k,n,m,len,block,ans; scanf("%d",&n); len=floor(sqrt(n)); if (n%len==0) block=n/len; else block=n/len+1; for (i=1;i<=block;++i) { ku[i][0]=len*(i-1)+1; ku[i][1]=min(n,len*i); } for (i=1;i<=n;++i) scanf("%d",&a[i]); for (i=1;i<=block;++i) for (j=ku[i][1];j>=ku[i][0];--j) { if (j+a[j]>ku[i][1]) { f[j][0]=1;f[j][1]=j+a[j]; } else { f[j][0]=f[j+a[j]][0]+1;f[j][1]=f[j+a[j]][1]; } } scanf("%d",&m);++m; while(--m) { scanf("%d%d",&i,&j); ++j; if (i==1) { ans=0; for (;j<=n;j=f[j][1]) ans+=f[j][0]; printf("%d\n",ans); } else { scanf("%d",&k); i=(j-1)/len+1;a[j]=k; for (;j>=ku[i][0];--j) { if (j+a[j]>ku[i][1]) { f[j][0]=1;f[j][1]=j+a[j]; } else { f[j][0]=f[j+a[j]][0]+1;f[j][1]=f[j+a[j]][1]; } } } } fclose(stdin); fclose(stdout); }