您的位置:首页 > 产品设计 > UI/UE

poj 3368 Frequent values -Sparse-Table

2016-07-16 16:28 423 查看
Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 16537Accepted: 5981
Description

You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.

Input

The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line contains n integers a1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}) separated by spaces. You can assume that for each i ∈ {1, ..., n-1}: ai ≤ ai+1. The following q lines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the
query.

The last test case is followed by a line containing a single 0.

Output

For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.

Sample Input

10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0


Sample Output

1
4
3


Source

Ulm Local 2007
(转自http://poj.org/problem?id=3368

  先讲一下题目大意,给出一个有n个数的不下降数列,和q个问题每个问题是求[a,b]中出现次数最多的数出现的次数,

有多组测试数据,当n = 0时测试结束

  方法有多种,第一种直接暴力枚举,就不讲了

  第二种用线段树,很多时候都不是完整的区间,怎么查?

  左右两端不完整区间连续的个数是可以求出来的,这个就比较简单,记录一下每个区间开始的位置

,然后再弄个数组,记录第i个数属于的区间的新编号,如果a不是一个短的开始就就用下一个区间的

开始减去a (就把编号 + 1就是下一个区间的编号),结束部分就基本一样了

  中间完整的区间就交给线段树查,最好是

  把一个区间当成长度为1的线段,建树,查的时候就对应这个编号就行了。

由于我不想写,所以就不给代码了,可以在网上查查

 


  第三种使用RMQ,反正又不会更新,再比较查询的时间复杂度,线段树的查询是O(log2N),而ST算法的查询时间O(1)(自行忽略

log函数执行的时间或者打表的时间),线段树建树的时间复杂度貌似是O(2N)左右(大约实际有效的节点是原数组的2

倍),ST算法的预处理时间是O(nlog2n)看起来差不多

  ST算法的思路和上面差不多,两端单独处理,中间交给ST算法去查。

另外:

  1.用位运算时一定要加上括号,位运算优先级很低,之前没在意,RE了几次

  2.每次完成一轮计算该清0的清0,该还原的还原

Code

#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
typedef class MyData{
private:
MyData(int from,int end,int _count):from(from),end(end),_count(_count){}
public:
int from;
int end;
int _count;
MyData(){}
static MyData getNULL(){
return MyData(0,0,0);
}
}MyData;
vector<MyData> list;
int a = -1000000,b;
int *pos;
int count1;
int f[100001][20];
int t;
int n,q;
void init(){
const int limit = list.size();
for(int i = 0;i < limit;i++)
f[i][0] = list[i]._count;
for(int j = 1; (1 << j) < limit;j++){
t = 1 << j;
for(int i = 0; i < limit && (i + t) < limit; i++){
f[i][j] = max(f[i][j - 1], f[ i + (1 <<  j - 1) ][j - 1]);  //位运算优先级低!!!打括号
         }
}
}
int main(){
while(true){
scanf("%d",&n);
if(n == 0) break;
scanf("%d",&q);
pos = new int[(const int)(n + 1)];
for(int i = 1;i <= n;i++){
scanf("%d",&b);
if(a == b){
list[list.size() - 1]._count++;
pos[i] = pos[i - 1];
}else{
if(!list.empty())
list[list.size() - 1].end = i - 1;
list.push_back(MyData::getNULL());
pos[i] = count1++;
list[list.size() - 1].from = i;
list[list.size() - 1]._count = 1;
}
a = b;
}
list[list.size() - 1].end = n;
init();
for(int i = 1;i <= q;i++){
scanf("%d%d",&a,&b);
if(pos[a] == pos){
printf("%d\n",b - a + 1);
continue;
}
if(pos[b] - pos[a] == 1){
int result = max(list[pos[a]].end - a + 1,b - list[pos[b]].from + 1);
printf("%d\n",result);
continue;
}
int ans = 0;
ans = max(list[pos[a]].end-a+1,b-list[pos[b]].from+1);
b = pos[b] - 1;
a = pos[a] + 1;
int k = (int)(log((double)b-a+1.0)/log(2.0));
int t2 = max(f[a][k],f[b-(1<<k)+1][k]);
ans = max(ans,t2);
printf("%d\n",ans);
}
delete[] pos;
list.clear();
count1 = 0;
a = -1000000;
}
return 0;
}


[b][后记]


  附赠调试这道题时所用的对拍器、比较程序和数据生成器

cmp.cpp:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char buf1[1000];
char buf2[1000];
FILE *fin1;
FILE *fin2;
int main(int argc, char* argv[]){
fin1 = fopen(argv[1],"r");
fin2 = fopen(argv[2],"r");
while(!(feof(fin1))&&!(feof(fin2))){
fscanf(fin1,"%s",buf1);
fscanf(fin2,"%s",buf2);
if(strcmp(buf1, buf2) != 0)    return 1;
}
if(feof(fin1) != feof(fin2)) return 1;
return 0;
}


md_fv.cpp:

#include<iostream>
#include<fstream>
#include<cstdlib>
#include<time.h>
using namespace std;
ofstream fout("fv.in");
int main(){

srand((unsigned)time(NULL));

int n = rand()%100 + 1;
int q = rand()%100 + 1;

fout<<n<<" "<<q<<endl;

int start = rand()%1000 - 500;
for(int i =1; i<= n;i++){
start += rand()%2;
fout<<start<<" ";
}

fout<<endl;
for(int i = 0;i < q;i++){
start = rand()%n + 1;
int end = min(rand()%(n - start + 1) + start,n);
fout<<start<<" "<<end<<endl;
}

fout<<"0"<<endl;
return 0;
}


test_fv.cpp:

#include<iostream>
#include<cstdlib>
#include<time.h>
using namespace std;
typedef bool boolean;
int statu;
boolean aFlag;
int main(){
system("g++ fv.cpp -o fv.exe");
system("g++ cmp.cpp -o cmp.exe");
system("g++ md_fv.cpp -o md_fv.exe");
system("g++ std.fv.cpp -o std.fv.exe");
for(int i = 0;i < 1000;i++){
aFlag = true;
system("md_fv");
system("std.fv");
clock_t begin = clock();
statu = system("fv");
clock_t end = clock();
cout<<"测试数据#"<<i<<":";
if(statu != 0){
cout<<"RuntimeError";
}else if(system("cmp fv1.out fv.out") != 0){
cout<<"WrongAnswer";
}else{
cout<<"Accepted";
aFlag = false;
}
cout<<"\t\tTime:"<<(end - begin)<<"ms"<<endl;
if(aFlag){
system("pause");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: