标签:size 情况 完全 read 复杂 编号 结构体 一个人 bzoj
题目描述
输入
输出
样例输入
5 4
1 2 3 4 5
1 2 1 1 3
5 5 1 2 2 4
2 4 2 0
3 4 2 1 4
样例输出
1
5
5
2
-1
题解
随机化+线段树
考虑如果区间中一个数的出现次数等于区间长度的一半,那么期望随机找两次即可找到该数。
所以理论上看,每次随机找20次,完全正确地处理500000个询问的概率约为0.62。而实际上由于数据水,随机15次即可AC。
然后就是找某数在区间中出现的次数,直接对每个数开一棵线段树即可。
时间复杂度$O(15n\log n)$,实际上本题很卡时(卡随机化),需要使用结构体写线段树才可以卡过。
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define N 500010
#define lson l , mid , a[x].ls
#define rson mid + 1 , r , a[x].rs
using namespace std;
struct data
{
int ls , rs , si;
}a[N * 60];
int w[N] , root[N] , tot;
inline int read()
{
int ret = 0; char ch = getchar();
while(ch < ‘0‘ || ch > ‘9‘) ch = getchar();
while(ch >= ‘0‘ && ch <= ‘9‘) ret = ret * 10 + ch - ‘0‘ , ch = getchar();
return ret;
}
void update(int p , int v , int l , int r , int &x)
{
if(!x) x = ++tot;
a[x].si += v;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(p , v , lson);
else update(p , v , rson);
}
int query(int b , int e , int l , int r , int x)
{
if(!x) return 0;
if(b <= l && r <= e) return a[x].si;
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid) ans += query(b , e , lson);
if(e > mid) ans += query(b , e , rson);
return ans;
}
int main()
{
srand(2333666);
int n , m , i , l , r , s , k , x , p , t;
n = read() , m = read();
for(i = 1 ; i <= n ; i ++ ) w[i] = read() , update(i , 1 , 1 , n , root[w[i]]);
while(m -- )
{
l = read() , r = read() , s = read() , k = read() , p = 0;
for(i = 1 ; i <= 15 ; i ++ )
{
t = w[rand() % (r - l + 1) + l];
if(query(l , r , 1 , n , root[t]) > (r - l + 1) >> 1)
{
p = t;
break;
}
}
if(!p) p = s;
printf("%d\n" , p);
for(i = 1 ; i <= k ; i ++ ) x = read() , update(x , -1 , 1 , n , root[w[x]]) , update(x , 1 , 1 , n , root[p]) , w[x] = p;
}
p = -1;
for(i = 1 ; i <= 15 ; i ++ )
{
t = w[rand() % n + 1];
if(a[root[t]].si > n >> 1)
{
p = t;
break;
}
}
printf("%d\n" , p);
return 0;
}
标签:size 情况 完全 read 复杂 编号 结构体 一个人 bzoj
原文地址:http://www.cnblogs.com/GXZlegend/p/7422455.html