分块 莫队 初见

学习了一下很基本的分块和莫队算法,因为不太会写曼哈顿距离最小生成树,所以就写了个分块版本的(分四种情况,大概这个意思吧)。。。

 

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);

}
View Code

 

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);

}
View Code

 

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);

}
View Code

 

你可能感兴趣的:(分块 莫队 初见)