题解 洛谷 P4203 【[NOI2008]糖果雨】
发现任何时刻不会出现两片颜色相同的云朵,因此云朵的颜色是不用考虑的,询问即为区间内有多少个云朵。
因为云朵的运动是在天空中往返的,具有周期性,且每个云朵运动速度都相同,所以可以用二元组 来表示一个云朵, 为该云朵左端点位于左边界时的时刻,即 , 为该云朵的长度,即 ,发现每个云朵都能用二维平面上的点 来表示。
接着考虑如何解决询问 ,首先对 转化为 。然后通过分类讨论来找到对于该询问在二维平面上对应的位置。设云朵的坐标为 ,得:
当 时,该云朵要到达询问的时刻还需再经过一段时间,经过这些时间后云朵的左端点要在询问的右端点左边,即 ,云朵的右端点要在询问的左端点右边,即 。
当 时,该云朵已经超过询问的时刻,因此其需要时光倒流,因为运动的周期性,其还是向右运动,把这些时间倒流后云朵的左端点要在询问的右端点左边,即 ,云朵的右端点要在询问的左端点右边,即 。
综上所述得询问在二维平面上对应的位置为 ,在平面上画出图来得:
发现图像为两个对称的五边形,若其超出了边界,就在另一端补上来,对于该图像不好进行统计,因此还需再进行转化,将其补成平行四边形得:
然后考虑对这两个平行四边形转化为矩形来进行统计,因为是询问存在性,而不是面积之类的信息,所以对于询问的范围进行转化,对于每个云朵的坐标也进行转化,然后进行询问就是合法的。对于右边向右倾斜的平行四边形,对其应用变换 ,对于左边向左倾斜的平行四边形,对其应用变换 ,这里加上 的原因是防止出现负坐标。然后对于这两个平行四边形分别用两个二维树状数组来维护,每个云朵在树状数组上进行加点删点时也应用相应的变换即可。
注意到当询问出现 的情况时, 和 这两个位置会算重,因此需要特判。
#include<bits/stdc++.h>
#define maxn 4010
#define maxm 1000010
#define lowbit(x) (x&(-x))
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,len;
struct node
{
int x,y;
}p[maxm];
struct BIT
{
int t[maxn][maxn];
void update(int x,int y,int v)
{
for(int i=x+1;i<=2*len;i+=lowbit(i))
for(int j=y+1;j<=4*len;j+=lowbit(j))
t[i][j]+=v;
}
int ask(int x,int y)
{
if(x<0||y<0) return 0;
int v=0;
for(int i=min(x+1,2*len);i;i-=lowbit(i))
for(int j=min(y+1,4*len);j;j-=lowbit(j))
v+=t[i][j];
return v;
}
int query(int x1,int y1,int x2,int y2)
{
return ask(x2,y2)-ask(x2,y1-1)-ask(x1-1,y2)+ask(x1-1,y1-1);
}
}T1,T2;
int main()
{
read(n),read(len);
for(int i=1;i<=n;++i)
{
int opt,t,c,l,r,d,v=0;
read(opt);
if(opt==1)
{
read(t),read(c),read(l),read(r),read(d);
p[c].x=(t-l*d+2*len)%(2*len),p[c].y=r-l;
T1.update(p[c].x,p[c].x+p[c].y,1),T2.update(p[c].x,p[c].y-p[c].x+2*len,1);
}
if(opt==2)
{
read(t),read(l),read(r),d=(r==len),t%=2*len;
v+=T1.query(t,t+l,t+r-d,4*len);
v+=T1.query(0,t+l-2*len,t+r-2*len,4*len);
v+=T2.query(t-r+d,l-t+2*len,t-1,4*len);
v+=T2.query(t-r+2*len,l-t,2*len,4*len);
printf("%d\n",v);
}
if(opt==3)
{
read(t),read(c);
T1.update(p[c].x,p[c].x+p[c].y,-1),T2.update(p[c].x,p[c].y-p[c].x+2*len,-1);
}
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· Winform-耗时操作导致界面渲染滞后
· Phi小模型开发教程:C#使用本地模型Phi视觉模型分析图像,实现图片分类、搜索等功能
· 语音处理 开源项目 EchoSharp
· drools 规则引擎和 solon-flow 哪个好?solon-flow 简明教程