bzoj 5016 一个简单的询问

THUWC 考了莫队(这个应该可以说吧)

然而不会莫队,签到失败,所以找到了一道长得差不多的题写一写

为什么这么长时间都没有发现这道题(半恼

给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出

get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次。

sol:

把一个询问拆成 4 个前缀询问,注意到 $\sum\limits_{x=0}^{\infty}get(l_1,r_1,x) \cdot get(l_2,r_2,x) = \sum\limits_{x=0}^{\infty}get(1,r_1,x) \cdot get(1,r_2,x) - \sum\limits_{x=0}^{\infty}get(1,l_1-1,x) \cdot get(1,r_2,x) - \sum\limits_{x=0}^{\infty}get(1,r_1,x) \cdot get(1,r_2 - 1,x) + \sum\limits_{x=0}^{\infty}get(1,l_1-1,x) \cdot get(1,l_2-1,x)$

然后每组询问就是一个二元组了(因为左端点都是 $1$) ,所以可以莫队,用两个 $cnt$ 数组记一下左边右边的每一个 $x$ 出现了多少次即可

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == ‘-‘) f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - ‘0‘;
    return x * f;
}
const int maxn = 50010;
int n,a[maxn];
int bl[maxn],tot,cntl[maxn],cntr[maxn];
LL ans[maxn];
struct Ques
{
    int l,r,flag,pos;
    Ques(){}
    Ques(int _1,int _2,int _3,int _4): l(_1),r(_2),flag(_3),pos(_4){}
    bool operator < (const Ques &b)const{return (bl[l] == bl[b.l]) ? (r < b.r) : (bl[l] < bl[b.l]);}
}qs[maxn << 2];
int main()
{
    n = read();
    for(int i=1;i<=n;i++)a[i] = read();
    int BLSIZE = sqrt(n);
    for(int i=1;i<=n;i++)bl[i] = i / BLSIZE;
    int q = read();
    for(int i=1;i<=q;i++)
    {
        int xl = read(),xr = read(),yl = read(),yr = read();
        qs[++tot] = Ques(xr,yr,1,i);
        if(xl > 1)qs[++tot] = Ques(xl - 1,yr,-1,i);
        if(yl > 1)qs[++tot] = Ques(xr,yl - 1,-1,i);
        if(xl > 1 && xr > 1)qs[++tot] = Ques(xl - 1,yl - 1,1,i);
    }
    sort(qs + 1,qs + tot + 1);
    int l = 0,r = 0;
    LL now = 0;
    for(int i=1;i<=tot;i++)
    {
        while(l < qs[i].l){l++;now += cntr[a[l]];cntl[a[l]]++;}
        while(r < qs[i].r){r++;now += cntl[a[r]];cntr[a[r]]++;}
        while(l > qs[i].l){cntl[a[l]]--;now -= cntr[a[l]];l--;}
        while(r > qs[i].r){cntr[a[r]]--;now -= cntl[a[r]];r--;}
        ans[qs[i].pos] += qs[i].flag * now;
    }
    for(int i=1;i<=q;i++)cout << ans[i] << endl;
}

原文地址:https://www.cnblogs.com/Kong-Ruo/p/10326348.html

时间: 2024-11-17 01:02:43

bzoj 5016 一个简单的询问的相关文章

【BZOJ5016】[Snoi2017]一个简单的询问 莫队

[BZOJ5016][Snoi2017]一个简单的询问 Description 给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出 get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次. Input 第一行,一个数字N,表示序列长度. 第二行,N个数字,表示a1-aN 第三行,一个数字Q,表示询问个数. 第4-Q+3行,每行四个数字l1,r1,l2,r2,表示询问. N,Q≤50000 N1≤ai≤N 1≤l1≤r1≤N 1≤l2≤r2≤N

bzoj 5016: [Snoi2017]一个简单的询问

Description 给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出 get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次. Input 第一行,一个数字N,表示序列长度.第二行,N个数字,表示a1-aN第三行,一个数字Q,表示询问个数.第4-Q+3行,每行四个数字l1,r1,l2,r2,表示询问.N,Q≤50000N1≤ai≤N1≤l1≤r1≤N1≤l2≤r2≤N注意:答案有可能超过int的最大值Output 对于每组询问,输出一行一

[BZOJ5016]一个简单的询问

给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出 get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次. Input 第一行,一个数字N,表示序列长度. 第二行,N个数字,表示a1-aN 第三行,一个数字Q,表示询问个数. 第4-Q+3行,每行四个数字l1,r1,l2,r2,表示询问. N,Q≤50000 N1≤ai≤N 1≤l1≤r1≤N 1≤l2≤r2≤N 注意:答案有可能超过int的最大值 Output 对于每组询问,输出一行一个数字

【bzoj5016】[Snoi2017]一个简单的询问 莫队算法

题目描述 给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出 get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次. 输入 第一行,一个数字N,表示序列长度. 第二行,N个数字,表示a1-aN 第三行,一个数字Q,表示询问个数. 第4-Q+3行,每行四个数字l1,r1,l2,r2,表示询问. N,Q≤50000 N1≤ai≤N 1≤l1≤r1≤N 1≤l2≤r2≤N 注意:答案有可能超过int的最大值 输出 对于每组询问,输出一行一个数字,表

bzoj5016 [Snoi2017]一个简单的询问

传送门 分析 我们发现可以通过容斥得到Ans = sum(1,R1,1,R2) - sum(1,R1,1,L2-1) - sum(1,L1-1,1,R2) + sum(1,L1-1,L2-1) 于是我们可以吧一个询问分成4部分 然后进行莫队即可 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include

【LOJ2254】SNOI2017一个简单的询问

莫队,每次询问的是两个区间,就把区间拆开,分开来算就好了. 借鉴了rank1大佬的玄学排询问的姿势. #include<bits/stdc++.h> #define N 50010 typedef long long ll; using namespace std; inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-

[Snoi2017]一个简单的询问

数据范围很容易让人想到莫队算法 但是对于每次询问有\(l_1,r_1,l_2,r_2\)四个参数 很不方便维护 所以可以将询问差分 \(get(l,r,x)=get(1,r,x)-get(1,l-1,x)\) \(get(l_1,r_1,x)*get(l_2,r_2,x)\) \(=get(1,r_1,x)*get(1,r_2,x)\) \(-get(1,l_1-1,x)*get(1,r_2,x)\) \(-get(1,r_1,x)*get(1,l_2-1,x)\) \(+get(1,l_1-1

Win32编程API 基础篇 -- 2.一个简单的窗口 根据英文教程翻译

一个简单的窗口 例子:简单的窗口 有时人们在IRC提问,”我应该怎样制作一个窗口”...嗯,这恐怕不是完全这么简单好回答!其实这并不难一旦你明白你在做什么,但在你得到一个可展示的窗口之前还有一些事情需要我们去做,我们只需要简单地聊聊快速做下笔记,这个问题就能被很简单的回答. 我很喜欢先动手再学习...一下就是一个简单的窗口的程序,我们将会简短的对它进行解释说明. 1 #include <windows.h> 2 3 const char g_szClassName[] = "myWi

5、使用Libgdx设计一个简单的游戏------雨滴

(原文:http://www.libgdx.cn/topic/49/5-%E4%BD%BF%E7%94%A8libgdx%E8%AE%BE%E8%AE%A1%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E6%B8%B8%E6%88%8F-%E9%9B%A8%E6%BB%B4) 在深入研究Libgdx提供的API之前,我们先来创建一个简单的游戏来感受一下libgdx各个功能.这里将简单的对一些功能做介绍. 使用的技术: 文件访问 清除屏幕 渲染图片 使