分块+莫队

分块:

分段预处理答案,在询问时,满足一整个块的,块间暴力;不满足完整一个区域的,块内直接暴力;

#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],num,block,n;
ll a[maxn],val[maxn];

void buid()
{
    block=sqrt(n);                      //块的大小
    num=n/block;if(n%block)num++;       //块的数量;
    for(int i=1;i<=num;i++)
        l[i]=(i-1)*block+1,r[i]=block*i;//每块的左右端点值
    r[num]=n;
    for(int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;        //每块i属于哪一块;
    //更新块内信息;
    for(int i=1;i<=num;i++)
    {
        for(int j=l[i];j<=r[i];j++)
            val[i]=max(val[i],a[j]);//块内最大值;
    }
}
void updata(int x,int y)
{
    a[x]+=y;
    val[belong[x]]=max(val[belong[x]],a[x]);
}
ll ask(int x,int y)
{
    ll ans=0;
    if(belong[x]==belong[y])//块内暴力
    {
        for(int i=x;i<=y;i++)
            ans=max(a[i],ans);
        return ans;
    }
    for(int i=x;i<=r[belong[x]];i++)//首端块内暴力;
        ans=max(a[i],ans);
    for(int i=belong[x]+1;i<belong[y];i++)//块间暴力;
        ans=max(val[i],ans);
    for(int i=l[belong[y]];i<=y;i++)//尾端块内暴力;
        ans=max(ans,a[i]);
    return ans;
}
int main()
{
    int q;
    scanf("%d%d",&n,&q);
    buid();
    while(q--){
        int op,p,x;
        scanf("%d%d%d",&op,&p,&x);
        if(op==1){
            updata(p,x);
        }else{
            printf("%lld\n",ask(p,x));
        }
    }
    return 0;
}

莫队:

将询问存储,经过一定的方式排序,减少冗余查询的算法。

例:http://codeforces.com/contest/617/problem/E

题目大意:求给定l和r之间,连续的异或和为k的对数;

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=1<<20;           //这里是坑;
typedef long long ll;

struct node{                    //询问区间
    int l,r,id;
}Q[maxn];

int n,m,k;
int a[maxn],pos[maxn];          //存数列异或的前缀和,每个数在哪个块
ll flag[maxn],ans[maxn];

int L=1,R=0;
ll res=0;                       //初始区间
bool cmp(node x,node y)         //将询问区间排序
{
    if(pos[x.l]==pos[y.l])      //同一个块,按照询问的右边界从小到大排序;
        return x.r<y.r;
    return pos[x.l]<pos[y.l];   //不同块时,按照询问的右边界从小到大排序;
}
void add(int x)
{
    res+=flag[a[x]^k];
    flag[a[x]]++;
}
void del(int x)
{
    flag[a[x]]--;
    res-=flag[a[x]^k];
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int sz=sqrt(n);             //分块;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        a[i]=a[i]^a[i-1];       //异或的前缀和;
        pos[i]=i/sz;            //每个i在哪个块里;
    }
    for(int i=1;i<=m;i++)       //输入询问
    {
        scanf("%d%d",&Q[i].l,&Q[i].r);
        Q[i].id=i;
    }
    sort(Q+1,Q+1+m,cmp);
    flag[0]=1;
    for(int i=1;i<=m;i++)
    {
        while(L<Q[i].l){        //将L加到l
            del(L-1);
            L++;
        }
        while(L>Q[i].l){
            L--;
            add(L-1);
        }
        while(R<Q[i].r)         //将R加到r
        {
            R++;
            add(R);
        }
        while(R>Q[i].r){        //将R减到r
            del(R);
            R--;
        }
        ans[Q[i].id]=res;

    }
    for(int i=1;i<=m;i++)
    {
        cout << ans[i] << endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Cloud-king/p/9692665.html

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

分块+莫队的相关文章

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)

分块 莫队 初见

学习了一下很基本的分块和莫队算法,因为不太会写曼哈顿距离最小生成树,所以就写了个分块版本的(分四种情况,大概这个意思吧)... cogs1775||bzoj2038 小Z的袜子 题目大意:静态区间查询不同种元素的个数. 思路:用莫队扫一下,然后分子分母同时乘2,就会发现,分母是组合数化简后的(r-l)*(r-l+1),分子是每种颜色个数的平方-区间元素(从相同颜色的当中选两个可重的,去掉两个是一个的),然后就很好处理了. #include<iostream> #include<cstdi

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