LOJ #6032 「雅礼集训 2017 Day2」水箱

本文介绍了一种使用扫描线算法解决特定问题的方法。通过并查集处理挡板被截断的情况,并针对不同操作需求(如要求区域有水或无水)进行处理。最终实现了对输入数据的有效管理和快速响应。

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

题目链接

https://loj.ac/problem/6032

题解

扫描线,先将每个操作按照y轴排序,考虑水从下面淹到上面。

对于挡板被截断的情况:并查集合并左侧和右侧的格子。

对于要求没有水的情况:如果水不淹到上面,那么它一定会被满足。

对于要求有水的情况:直接把下面的全淹了,再来更新答案。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

const int maxn=100000;

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

struct data
{
  int op,x,y;

  data(int op_=0,int x_=0,int y_=0)
  {
    op=op_;
    x=x_;
    y=y_;
  }

  bool operator <(const data &other) const
  {
    if(y==other.y)
      {
        return op<other.op;
      }
    return y<other.y;
  }
};

namespace dsu
{
  int fa[maxn+10];

  inline int clear()
  {
    memset(fa,0,sizeof fa);
    return 0;
  }

  int find(int x)
  {
    return fa[x]?fa[x]=find(fa[x]):x;
  }
}

data d[maxn*2+10];
int f[maxn+10],ans[maxn+10],cnt,t,n,m,lastans;

int main()
{
  t=read();
  while(t--)
    {
      cnt=0;
      memset(f,0,sizeof f);
      memset(ans,0,sizeof f);
      lastans=0;
      dsu::clear();
      n=read();
      m=read();
      for(int i=1; i<n; ++i)
        {
          int h=read();
          d[++cnt]=data(-1,i,h);
        }
      while(m--)
        {
          int x=read(),y=read(),op=read();
          d[++cnt]=data(op,x,y);
        }
      std::sort(d+1,d+cnt+1);
      for(int i=1; i<=cnt; ++i)
        {
          if(d[i].op==-1)
            {
              int x=dsu::find(d[i].x),y=dsu::find(d[i].x+1);
              dsu::fa[y]=x;
              f[x]+=f[y];
              ans[x]+=ans[y];
              lastans=std::max(lastans,ans[x]);
            }
          else if(d[i].op==0)
            {
              lastans=std::max(lastans,++ans[dsu::find(d[i].x)]);
            }
          else
            {
              int x=dsu::find(d[i].x);
              lastans=std::max(lastans,ans[x]=std::max(ans[x],++f[x]));
            }
        }
      printf("%d\n",lastans);
    }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值