3809: Gty的二逼妹子序列

Time Limit: 80 Sec  Memory Limit: 28 MB
Submit: 1634  Solved: 482
[Submit][Status][Discuss]

Description

Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。
 
对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数。
 
为了方便,我们规定妹子们的美丽度全都在[1,n]中。
 
给定一个长度为n(1<=n<=100000)的正整数序列s(1<=si<=n),对于m(1<=m<=1000000)次询问“l,r,a,b”,每次输出sl...sr中,权值∈[a,b]的权值的种类数。

Input

第一行包括两个整数n,m(1<=n<=100000,1<=m<=1000000),表示数列s中的元素数和询问数。
 
第二行包括n个整数s1...sn(1<=si<=n)。
 
接下来m行,每行包括4个整数l,r,a,b(1<=l<=r<=n,1<=a<=b<=n),意义见题目描述。
 
保证涉及的所有数在C++的int内。
 
保证输入合法。

Output

对每个询问,单独输出一行,表示sl...sr中权值∈[a,b]的权值的种类数。

Sample Input

10 10
4 4 5 1 4 1 5 1 2 1
5 9 1 2
3 4 7 9
4 4 2 5
2 3 4 7
5 10 4 4
3 9 1 1
1 4 5 9
8 9 3 3
2 2 1 6
8 9 1 4

Sample Output

2
0
0
2
1
1
1
0
1
2

HINT

样例的部分解释:
5 9 1 2
子序列为4 1 5 1 2
在[1,2]里的权值有1,1,2,有2种,因此答案为2。
 
3 4 7 9
子序列为5 1
在[7,9]里的权值有5,有1种,因此答案为1。
4 4 2 5
子序列为1
没有权值在[2,5]中的,因此答案为0。
 
2 3 4 7
子序列为4 5
权值在[4,7]中的有4,5,因此答案为2。
建议使用输入/输出优化。

= =,我之前看卿学姐的代码,思考着他的莫队+分块是怎么做的,想着想着就发现暂时不清楚怎么分块,于是打算自己尝试写写看莫队+线段树来更新,然后果然TLE,因为这样的复杂度是O(n^1.5 * logn)

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
inline int read(){
int x=,f=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 1e5 + ;
const int maxm = + ;
int block, pos[maxn], sz, s[maxn];
struct Point{
int l, r, ca, cb, id;
}q[maxm];
int res[maxm];
bool cmp(Point a, Point b){
if(pos[a.l]==pos[b.l])
return a.r<b.r;
return pos[a.l]<pos[b.l];
}
int n, m;
struct Sedment_tree{
int colorcnt, colornum;
}tree[maxn << ]; inline void push_up(int o){
int lb = o << , rb = o << | ;
tree[o].colornum = tree[lb].colornum + tree[rb].colornum;
} void update(int p, int l, int r, int o, int val){
if (p == l && p == r){
tree[o].colorcnt += val;
if (tree[o].colorcnt == ) tree[o].colornum = ;
if (tree[o].colorcnt == ) tree[o].colornum = ;
return ;
}
int mid = (l + r) / ;
if (p <= mid) update(p, l, mid, o << , val);
if (p > mid) update(p, mid + , r, o << | , val);
push_up(o);
} void add(int x){
update(s[x], , n, , );
} void del(int x){
update(s[x], , n, , -);
} int query(int ql, int qr, int l, int r, int o){
int ans = ;
if (ql <= l && qr >= r){
ans += tree[o].colornum; return ans;
}
int mid = (l + r) / ;
if (ql <= mid) ans += query(ql, qr, l, mid, o << );
if (qr > mid) ans += query(ql, qr, mid + , r, o << | );
return ans;
} int main(){
n = read(), m = read();
sz = sqrt(n);
for (int i = ; i <= n; i++){
s[i] = read();
pos[i] = (i - ) / sz;
}
for (int i = ; i <= m; i++){
q[i].l = read(), q[i].r = read(), q[i].ca = read(), q[i].cb = read();
q[i].id = i;
}
sort(q + , q + + m, cmp);
int L = , R = ;
for (int i = ; i <= m; i++){
while (L > q[i].l){
L--; add(L);
}
while (R < q[i].r){
R++; add(R);
}
while (L < q[i].l){
L++; del(L - );
}
while (R > q[i].r){
R--; del(R + );
}
res[q[i].id] = query(q[i].ca, q[i].cb, , n, );
}
for (int i = ; i <= m; i++){
printf("%d\n", res[i]);
}
return ;
}

(好吧,隔了好久重新看了一下这题,发现是自己傻逼了,应该是可以用线段树的....吧?,具体怎么用的话就是修改一下add和del函数就好了,大致修改的和分块差不多?不过好像最坏情况还是会TLE唉)

因此改为莫队+分块吧

然后思考了一下,我们对于询问区间进行莫队离线操作即可。然后对于修改操作,我们就利用分块来控制颜色区间即可。

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
inline int read(){
int x=,f=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 1e5 + ;
const int maxm = + ;
int block, pos[maxn], sz, belong[maxn], num, l[maxn], r[maxn], cnt[maxn];
///pos是莫队算法,表示目前这个询问区间是哪个块的
///belong是分块,表示目前这个颜色是属于哪个块的
int s[maxn];
struct Point{
int l, r, ca, cb, id;
}q[maxm];
int res[maxm], color[maxn];
bool cmp(Point a, Point b){
if(pos[a.l]==pos[b.l])
return a.r<b.r;
return pos[a.l]<pos[b.l];
}
int n, m; void build(){
block = sqrt(n); num = n / block;
if (n % block) num++;
for (int i = ; i <= num; i++){
l[i] = (i - ) * block + ; r[i] = i * block;
}
r[num] = n;
for (int i = ; i <= n; i++){
belong[i] = (i - ) / block + ;
}
} void add(int x){
color[x]++;
if(color[x] == ) cnt[belong[x]]++;
} void del(int x){
color[x]--;
if(color[x] == ) cnt[belong[x]]--;
} int query(int x, int y){
int ans = ;
if (belong[x] == belong[y]){
for (int i = x; i <= y; i++) if (color[i]) ans++;
return ans;
}
for (int i = x; i <= r[belong[x]]; i++){
if (color[i]) ans++;
}
for (int i = l[belong[y]]; i <= y; i++){
if (color[i]) ans++;
}
for (int i = belong[x] + ; i < belong[y]; i++)
ans += cnt[i];
return ans;
} int main(){
n = read(), m = read();
sz = sqrt(n);
for (int i = ; i <= n; i++){
s[i] = read();
pos[i] = (i - ) / sz;
}
for (int i = ; i <= m; i++){
q[i].l = read(), q[i].r = read(), q[i].ca = read(), q[i].cb = read();
q[i].id = i;
}
sort(q + , q + + m, cmp);
int L = , R = ;
build();
for (int i = ; i <= m; i++){
while (L > q[i].l){
L--; add(s[L]);
}
while (R < q[i].r){
R++; add(s[R]);
}
while (L < q[i].l){
L++; del(s[L - ]);
}
while (R > q[i].r){
R--; del(s[R + ]);
}
res[q[i].id] = query(q[i].ca, q[i].cb);
}
for (int i = ; i <= m; i++){
printf("%d\n", res[i]);
}
return ;
}

关键:深刻了解莫队算法和分块

莫队+分块 BZOJ 3809的更多相关文章

  1. 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex

    题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...

  2. [BZOJ 3585] mex 【莫队+分块】

    题目链接:BZOJ - 3585 题目分析 区间mex,即区间中没有出现的最小自然数. 那么我们使用一种莫队+分块的做法,使用莫队维护当前区间的每个数字的出现次数. 然后求mex用分块,将权值分块(显 ...

  3. Bzoj 3236: [Ahoi2013]作业 莫队,分块

    3236: [Ahoi2013]作业 Time Limit: 100 Sec  Memory Limit: 512 MBSubmit: 1113  Solved: 428[Submit][Status ...

  4. BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块

    BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块 Description Autumn和Bakser又在研究Gty的妹子序列了 ...

  5. BZOJ_3585_mex && BZOJ_3339_Rmq Problem_莫队+分块

    BZOJ_3585_mex && BZOJ_3339_Rmq Problem_莫队+分块 Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一 ...

  6. BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块

    题目描述 输入 输出 样例输入 3 4 1 2 2 1 2 1 3 1 2 1 1 1 3 1 3 2 3 2 3 样例输出 2 2 1 1 3 2 2 1 提示 N=100000,M=1000000 ...

  7. CFGym101138D Strange Queries 莫队/分块

    正解:莫队/分块 解题报告: 传送门 ummm这题耗了我一天差不多然后我到现在还没做完:D 而同机房的大佬用了一个小时没有就切了?大概这就是大佬和弱鸡的差距趴QAQ 然后只是大概写下思想好了因为代码我 ...

  8. [BZOJ3585]mex(莫队+分块)

    显然可以离线主席树,这里用莫队+分块做.分块的一个重要思想是实现修改与查询时间复杂度的均衡,这里莫队和分块互相弥补. 考虑暴力的分块做法,首先显然大于n的数直接忽略,于是将值域分成sqrt(n)份,每 ...

  9. 小Z的袜子(莫队分块)题解

    小Z的袜子(hose) 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜 ...

随机推荐

  1. QT中文乱码解决方法

    由于我毕设的界面是用Qt做的,之前没怎么接触过Qt,所以实现过程中遇到不少小问题,头一个就是这个. 现如今宝宝将其记录下来,供同样有需要的同学或者自己以后方便查阅. 1.所有文件编码格式须一致 不统一 ...

  2. python 动态获取当前运行的类名和函数名的方法

    一.使用内置方法和修饰器方法获取类名.函数名 python中获取函数名的情况分为内部.外部,从外部的情况好获取,使用指向函数的对象,然后用__name__属性 复制代码代码如下: def a():pa ...

  3. MacOS下搭建python环境

    1. 安装须知 Mac OS自身其实已经带有Python,版本为2.7.X,这个Python主要用于支持系统文件和XCode,所以我们在安装新的Python版本时候最好不要影响这部分. 这里就会出现一 ...

  4. 第5章 Linux 常用网络指令

    网络参数设定使用的指令 手动/自动设定与启动/关闭 IP 参数: ifconfig, ifup, ifdown ifconfig :查询.设定网络卡与 IP 网域等相关参数:ifup, ifdown: ...

  5. Eureka服务注册过程

    上篇博客<SpringCloud--Eureka服务注册和发现>介绍了Eureka的基本功能,这篇我们来聊聊eureka是如何实现的. 上图是eureka的架构图,Eureka分为Serv ...

  6. php中ob缓存机制

    1.ob缓存运行方式 2.注意:在程序中如果开启ob_start(),所有的echo输出都会保存到ob缓存中,可以使用ob系列函数进行操作,如果没有,默认情况下,在程序执行结束,会把缓存中的数据发送给 ...

  7. linux学习笔记4

    查看当前系统还有哪些用户 who 字符计数 wc -l(line) 可以统计有多少行 -w(word) 可以统计有多少个单词 -c(character) 可以统计有多少个字符  切个字符 - 排序 l ...

  8. hdu 6400 Parentheses Matrix

    题目链接 Problem Description A parentheses matrix is a matrix where every element is either '(' or ')'. ...

  9. bzoj4569-萌萌哒

    题目 有一个长度为\(n\)的十进制数,用\(s\)表示.有\(m\)个限制条件,每个条件形如:\((l_1,r_1,l_2,r_2)\),表示\(s[l_1:r_1]=s[l_2:r_2]\). 现 ...

  10. 安装lighttpd

    依赖包: zlib,pcre,cronolog,bzip2, 1: 将lighttpd的原码包.以土豆现用lighttpd配置文件为基础的lighttpd.conf文件.日志轮循工具cronolog  ...