bzoj 5288: [Hnoi2018]游戏 随机化

本文介绍了一种区间拓展算法,通过拓扑排序和随机化处理,实现了高效的区间查询。该算法适用于处理大规模数据集中的区间覆盖问题,特别是对于具有单向性的区间拓展场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

n个房间排成一排, 相邻房间之间有1道门,一部分的门上有锁,其余的门可以直接打开
告诉你有锁的门的这把锁的钥匙的位置,询问q次,问从S可否到达T
1n,p106,0m<n,1x,y,Si,Ti<n,x1≤n,p≤106,0≤m<n,1≤x,y,Si,Ti<n,保证x不重复

分析

一种搞法就是,先每个点找到右端点,然后再找左端点,然后再左右分别拓展,(然后就可以拿到80分,这个想想就很优秀,因为只有一些进来这个拓展区间很多次才能卡掉)

考虑100分的做法, 发现区间的拓展具有单向性,其实可以拓扑来做

但是一种优美的解法,把所有点random_shufflerandom_shuffle一下来拓展,就行了
时间复杂度大概是O(nlogn)O(nlogn)的,想想也觉得很优秀

种子选19260818

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
struct node{int l,r;}q[N];
int p[N]; int ml[N],mr[N],id[N]; int fa[N];
int Find(int x){return (fa[x]==x) ? fa[x] : fa[x] = Find(fa[x]);}
void extend(int i)
{
  while(1)
  {
    bool bk = 0;
    if(ml[i] <= id[ml[i]-1] && id[ml[i]-1] <= mr[i]){ml[i] = min(ml[i],ml[Find(ml[i]-1)]); mr[i] = max(mr[i],mr[Find(mr[i]-1)]); bk = 1;}
    if(ml[i] <= id[mr[i]] && id[mr[i]] <= mr[i]){ml[i] = min(ml[i],ml[Find(ml[i]+1)]); mr[i] = max(mr[i],mr[Find(mr[i]+1)]); bk = 1;}
    if(!bk) break;
  }
}

int main()
{
  srand(19260817);

  int n = read(); int m = read(); int qq = read();

  for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),id[q[i].l] = q[i].r;
  for(int i=1;i<=n;i++) ml[i] = mr[i] = i;

  for(int i=1;i<=n;i++) fa[i] = i;

  for(int i=n-1;i>=1;i--) if(!id[i]) mr[i] = mr[i+1],fa[Find(i)] = Find(i+1);
  for(int i=1;i<n;i++) if(!id[i]) ml[i+1] = ml[i];

  for(int i=1;i<=n;i++) p[i] = i; random_shuffle(p+1,p+n+1);
  for(int i=1;i<=n;i++) if(fa[p[i]] == p[i]) extend(p[i]);

  while(qq--)
  {
    int x = read(); int y = read();
    if(ml[Find(x)] <= y && y <= mr[Find(x)]) printf("YES\n");
    else printf("NO\n");
  }


  // cout<<(double)(clock())<<endl;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值