分块 莫队 初见

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

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

时间: 2024-08-12 16:20:04

分块 莫队 初见的相关文章

HDU 5145 分块 莫队

给定n个数,q个询问[l,r]区间,每次询问该区间的全排列多少种. 数值都是30000规模 首先考虑计算全排列,由于有同种元素存在,相当于每次在len=r-l+1长度的空格随意放入某种元素即$\binom{len}{k_1}$,那么下种元素即为$\binom{len-k_1}{k2}$,以此类推,直至最后直接填满,那么全排列为${\frac{len!}{k_1!k_2!…k_n!}}$ 然后可以发现可以直接O(1)求得左右相邻区间的值(就是乘或除),那么考虑分块莫队. /** @Date : 2

【BZOJ-3809】Gty的二逼妹子序列 分块 + 莫队算法

3809: Gty的二逼妹子序列 Time Limit: 80 Sec  Memory Limit: 28 MBSubmit: 1072  Solved: 292[Submit][Status][Discuss] Description Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题. 对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数. 为了方便,我们规定妹子们的美丽度全都在[1,n]中. 给定一个长度为n(1<=n<=100000)

分块+莫队

分块: 分段预处理答案,在询问时,满足一整个块的,块间暴力:不满足完整一个区域的,块内直接暴力: #include <cstdio> #include <algorithm> #include <iostream> #include <cmath> //提交SE; using namespace std; const int maxn=1e5+10; typedef long long ll; int belong[maxn],l[maxn],r[maxn]

AcWing 251. 小Z的袜子| 分块+莫队

传送门 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿. 终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命. 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R的袜子中随机选出两只来穿. 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子. 当然,小Z希望这个概率尽量高,所以他可能会询问多个(

莫队算法---基础知识介绍(转载)

莫队算法 莫队算法可用于解决一类可离线且在得到区间[l,r][l,r]的答案后,能在O(1)O(1)或O(log2n)O(log2?n)得到区间[l,r+1][l,r+1]或[l−1,r][l−1,r]的答案的问题 先看这样一个问题: 给出n个数字,m次询问,每次询问在区间[li,ri][li,ri]之间任选两个数字相等的概率是多少.(n,q<=50000)(小z的袜子) 在区间[l,r][l,r]中,这个概率是: ∑vi=1C(2,f(i))C(2,r−l+1)∑i=1vC(2,f(i))C(

NBUT1457 Sona 莫队算法

由于10^9很大,所以先离散化一下,把给你的这一段数哈希 时间复杂度O(nlogn) 然后就是分块莫队 已知[L,R],由于事先的离散化,可以在O(1)的的时间更新[l+1,r],[l,r+1],[l-1,r],[l,r-1]时间复杂度O(n*sqrt(n)): 代码如下,速度并不是很快(我比较喜欢手动的去重,unique一直没怎么用过) /*96655 's source code for B Memory: 3744 KB Time: 2968 MS Language: G++ Result

莫队算法学习笔记【BZOJ2038:小Z的袜子】【SPOJ3267:D-query】

很久以前傻乎乎地看来源奇怪的资料的时候被各种曼哈顿弄晕了. 然后现在学会的是分块方法.另新创一个分块方法. 让我们考虑这样一个区间询问问题…… 它有如下的性质: 0,n个数,Q个询问. 1,它没有修改操作,这意味着我们可以按我们喜欢的次序跟询问玩耍.实际上后面会讲到我们完全可以按任意次序玩耍. 2,如果我们知道区间询问 [L , R] 对应的值,我们可以轻易求出 [L±1 , R] 和 [L , R±1] 的值. (其实如果限制增加,比如只能求 [L+1 , R] 和 [L , R-1] 的值,

【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)

学习了树上莫队,树分块后对讯问的$dfs序$排序,然后就可以滑动树链处理答案了. 关于树链的滑动,只需要特殊处理一下$LCA$就行了. 在这里一条树链保留下来给后面的链来转移的$now$的为这条树链上所有点除去$LCA$的颜色种数.因为如果要考虑$LCA$情况就太多了,不如单独考虑$LCA$. 转移后加上当前链的$LCA$进行统计,然后再去掉这个$LCA$更新一下$now$值给后面的链转移. 这都是我的理解,说的有点不清楚,具体请看vfk的题解 OTZ 虽然不是这道题,但是通过这篇博客学习树上莫

【二维莫队】【二维分块】bzoj2639 矩形计算

<法一>二维莫队,对n和m分别分块后,对块从上到下从左到右依次编号,询问以左上角所在块编号为第一关键字,以右下角标号为第二关键字排序,转移时非常厉害. O(q*n*sqrt(n)). #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 201 #define M 100001 struct LiSan{int p,v;}t[N*N]; bool