洛谷3765总统选举暨洛谷5月月赛R1B题

传送门
这题我考场上花了大量时间思考与打代码,最后应该是花费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 r+1的rank就AC了。这可能是因为权值线段树的区间范围是死的1到n,treap的节点数却不是。
但是,哪位大佬能解释一下,为什么参数的调整这么玄学?(辣鸡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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值