bzoj 2054 并查集

61 篇文章 0 订阅
15 篇文章 0 订阅

题意:给定一个序列,多次将某个区间染成某种颜色,求最后每个点是什么颜色

由于只求最后染的颜色,所以倒着染

这样一个位置最多只需要染一次,染过就不需要再染

也就是说,对于当前染色,区间内已经染色的位置这次染色就要直接跳过,即只染区间内还没有被染色的

并查集的一个经典神助攻:删除一个数后快速找到它后面第一个没有删除的数(处理完一个位置后快速找打它后面第一个需要处理的位置)

这样就能保证每个位置只被染一次

时间复杂度O(n+m)

这个神助攻经常被用来“每个位置最多只会被处理一次”和“标记”和“快速找到最近的满足条件的位置”,常和离线、预处理、“正难则反”等结合,非常腻害

{$M 100000000}
var
        n,m,p,q,l,r,c   :longint;
        father,a        :array[0..1000010] of longint;
        i               :longint;

function get_father(x:longint):longint;
begin
   if x=father[x] then exit(x);
   father[x]:=get_father(father[x]);
   exit(father[x]);
end;

begin
   read(n,m,p,q);
   for i:=1 to n+1 do father[i]:=i;
   for i:=m downto 1 do
   begin
      l:=(i*p+q) mod n+1;
      r:=(i*q+p) mod n+1;
      if l>r then
      begin
         c:=l; l:=r; r:=c;
      end;
      l:=get_father(l);
      while l<=r do
      begin
         a[l]:=i;
         father[l]:=get_father(l+1);
         l:=get_father(l+1);
      end;
   end;
   for i:=1 to n do writeln(a[i]);
end.
——by Eirlys



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值