NOI online 2022丹钓战

看到这么个东西赛时想用莫队,但是打假了,所以就有了下面这个不三不四的代码

也就是很裸的暴力

void Push(int st,int ed){
    for(int i=st;i<=ed;++i){
        while(!q.empty()){
            Pair tmp=q.back();
            if(tmp.a == data[i].a || tmp.b<=data[i].b){
                q.pop_back();
            }
            else break;
        }
        q.push_back(data[i]);
        if(q.size()==1)ans++;
    }
}
     for(int i=1;i<=Q;++i){
         que[i].l=read(),que[i].r=read(),que[i].id=i;
     } 
     sort(que+1,que+Q+1,cmp);
     int l=0,r=0;
     for(int i=1;i<=Q;++i){
         if(l<que[i].l){
             q=deque<Pair>(),ans=0,l=que[i].l,r=que[i].r;
             Push(que[i].l,que[i].r); 
             que[i].ans=ans;           
             continue;
         }
         if(l==que[i].l){
             if(r<que[i].r){
                Push(r+1,que[i].r);
                r=que[i].r;
                que[i].ans=ans;
                continue;
             }
             if(r==que[i].r){
                que[i].ans=ans;
                continue;
             }
             if(r>que[i].r){
                q=deque<Pair>(),ans=0,r=que[i].r;
                Push(que[i].l,que[i].r); 
                que[i].ans=ans;
             }
         }    
     }
     sort(que+1,que+Q+1,cmp1);
     for(int i=1;i<=Q;++i){
         printf("%d\n",que[i].ans);
     }

对于每一个询问,l肯定可以“成功”毋庸置疑。对于i,如果满足题目中的条件就入栈,否则i就是成功的。那些可以放进去的点对于答案没有贡献,暴力解法的瓶颈就在于遍历了这些没有用的点。

我们预处理出每一个点到的下一个"成功"点(初值为n+1),查询时从lr一直跳就可以了。

for(int i=1;i<=n;++i){
    while(!s.empty() && !(a[i]!=a[s.top()] && b[i]<b[s.top()])){
          to[s.top()]=i;s.pop();
    }
    s.push(i);
}

for(int i=1;i<=q;++i){
    int ans=0;
    int l=read(),r=read();
    while(l<=r){
         ans++;l=to[l];
    }
    printf("%d\n",ans);
}

但是如果所有的点都是成功点,这种算法会被卡到n2。由于是不断地往后跳可以用倍增优化

for(int i=1;i<=n;++i){
    while(!s.empty() && !(a[i]!=a[s.top()] && b[i]<b[s.top()])){
         to[s.top()][0]=i;s.pop();
    }
    s.push(i);
}
for(int i=1;i<=20;++i){
    for(int j=1;j<=n;++j){
        to[j][i]=to[to[j][i-1]][i-1];
    }
}
for(int i=1;i<=q;++i){
    int l=read(),r=read();
    for(int j=20;j>=0;--j){
        if(to[l][j] && to[l][j]<=r){
            l=to[l][j];ans+=(1<<j);
        }
    }
    printf("%d\n",ans);
}

民间数据倍增比不加倍增慢了将近一倍...

posted @   Chano_sb  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示