传送门
这题我考场上花了大量时间思考与打代码,最后应该是花费4小时得到70分(乐多赛制罚成57分),太浪费时间了,一定是因为我太弱了。
我已开始的想法是对于每个询问区间,在区间里随机选很多次数,统计一下每个数的出现次数是否满足条件即可。但是,随机数不是很稳定,万一区间长度10000,有5100个1,4900个2,然后发现100次随机,有49次是2,51次是1,不就gg了?
于是,我决定,每次询问随机A次,如果一个数在A次随机中出现超过B次,那么强行用数据结构(具体地说,我赛场上是对每种数x,建立一颗权值线段树,对于每一位,若等于x,权值赋成1,否则赋成0)统计一下这个数在区间中出现次数是否超过区间长度的一半即可。
一开始我取A=30,B=10,然后是50分。
后来我把B改成7,是70分。
然后就不敢改了。
比赛结束后,我把B改成5,90分,被卡常。再把用的数据结构从动态开点权值线段树变成treap,每次查
l
与
但是,哪位大佬能解释一下,为什么参数的调整这么玄学?(辣鸡rand()还我血汗分)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<fstream>
#include<cmath>
#include<cctype>
#include<stack>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
inline int getint(){
int x=0;
char c=getchar();
while(!isdigit(c))c=getchar();
for(;isdigit(c);c=getchar())x=x*10+c-48;
return x;
}
int buf[10];
inline void putint(int x){
int xb=0;
for(;x;x/=10)buf[++xb]=x%10;
for(;xb;--xb)putchar(buf[xb]+48);
}
const int N=500010,maxn=6000000,K=N<<1;
class treap{
private:
struct node{
node *l,*r;
int p,size,w;
int v;//kg
node(int _v):v(_v){
l=r=NULL;
p=rand();
w=size=1;
}
void maintain(){
size=w;
if(l!=NULL)size+=l->size;
if(r!=NULL)size+=r->size;
}
};
node*head;
void lturn(node* &x){
node*t=x->r;
x->r=t->l;
t->l=x;
x->maintain();
t->maintain();
x=t;
}
void rturn(node* &x){
node*t=x->l;
x->l=t->r;
t->r=x;
x->maintain();
t->maintain();
x=t;
}
void ins(node* &o,int y){
if(o==NULL)o=new node(y);
else if(y>o->v){
ins(o->r,y);
if(o->r->p>o->p)lturn(o);
}else if(y<o->v){
ins(o->l,y);
if(o->l->p>o->p)rturn(o);
}else ++o->w;
o->maintain();
}
void del(node* &x,int y){
if(x==NULL)return;
if(y>x->v)del(x->r,y);
else if(y<x->v)del(x->l,y);
else{
if(x->w>1){
--x->size;
--x->w;
return;
}
if(x->l==NULL){
node*z=x;
x=x->r;
delete z;
return;
}
if(x->r==NULL){
node*z=x;
x=x->l;
delete z;
return;
}
if(x->l->p>x->r->p){
rturn(x);
del(x->r,y);
}else{
lturn(x);
del(x->l,y);
}
}
if(x!=NULL)--x->size;
}
public:
void insert(int x){
ins(head,x);
}
void erase(int x){
del(head,x);
}
int rank(int y){
node*x=head;
int ans=0;
while(x!=NULL){
int s=0;
if(x->l!=NULL)s=x->l->size;
if(y==x->v)return ans+s+1;
if(y>x->v){
ans+=s+x->w;
x=x->r;
}else x=x->l;
}
return ans+1;
}
int lessnum(int y){
return rank(y)-1;
}
int morenum(int y){
node*x=head;
int ans=0;
while(x!=NULL){
int s=0;
if(x->r!=NULL)s=x->r->size;
if(y==x->v)return ans+s;
if(y<x->v){
ans+=s+x->w;
x=x->l;
}else x=x->r;
}
return ans;
}
int kth(int y){
node*x=head;
for(;;){
int u=0,v=x->w;
if(x->l!=NULL)u=x->l->size;
if(u<y && u+v>=y)return x->v;
if(y>u+v){
x=x->r;
y-=u+v;
}else x=x->l;
}
}
int prev(int y){
node*x=head,*t=NULL;
while(x!=NULL){
if(x->v>=y)x=x->l;
else{
t=x;
x=x->r;
}
}
if(t==NULL)return -(1<<30);
else return t->v;
}
int succ(int y){
node*x=head,*t=NULL;
while(x!=NULL){
if(x->v<=y)x=x->r;
else{
t=x;
x=x->l;
}
}
if(t==NULL)return 1<<30;
else return t->v;
}
int size(){
return head->size;
}
bool find(int y){
node*x=head;
for(;x!=NULL &&x->v!=y;y>x->v?x=x->r:x=x->l);
return x!=NULL;
}
}t[N];
int n,i,m,rt[N],l,r,s,k,b[K],c[N],x,d[N],e[10],j,len,f[K];
int main(){
n=getint();
m=getint();
for(i=1;i<=n;++i){
d[i]=getint();
t[d[i]].insert(i);
}
srand(time(0));
while(m--){
l=getint();
r=getint();
s=getint();
k=getint();
for(i=1;i<=k;++i)f[i]=getint();
j=0;
len=r-l+1;
for(i=1;i<=30;++i){
c[i]=rand()%len+l;
++b[d[c[i]]];
}
for(i=1;i<=30;++i){
if(b[d[c[i]]]>5)e[++j]=d[c[i]];
b[d[c[i]]]=0;
}
for(i=1;i<=j;++i)
if(t[e[i]].rank(r+1)-t[e[i]].rank(l)>len>>1)break;
if(j && i<=j)x=e[i];
else x=s;
putint(x);
putchar('\n');
for(i=1;i<=k;++i){
t[d[f[i]]].erase(f[i]);
d[f[i]]=x;
t[d[f[i]]].insert(f[i]);
}
}
for(i=1;i<=30;++i){
c[i]=rand()%n+1;
++b[d[c[i]]];
}
for(i=1;i<=30;++i){
if(b[d[c[i]]]>5)e[++j]=d[c[i]];
b[d[c[i]]]=0;
}
for(i=1;i<=j;++i)if(t[e[i]].rank(r+1)-t[e[i]].rank(l)>n>>1)break;
if(j && i<=j)printf("%d\n",e[i]);
else puts("-1");
return 0;
}