码迷,mamicode.com
首页 > 其他好文 > 详细

分块 莫队 初见

时间:2015-03-29 15:00:23      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:

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

 

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

 

分块 莫队 初见

标签:

原文地址:http://www.cnblogs.com/Rivendell/p/4375683.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!