HDU5283 SENOIR'S FISH【线段树】

传送门


PROBLEM

在这里插入图片描述


SOL

//一开始看错了题面,以为“网”是动态的,头脑一片空白

既然渔网不动,又是以鱼的编号为下标询问,显然不能基于鱼的坐标解决问题

考虑暴力处理每一个修改,对于鱼的x坐标,只加不减(y坐标同理)。换而言之,如果鱼已出网,便可不用考虑。

一、将 X 1 , Y 1 , X 2 , Y 2 X1,Y1,X2,Y2 X1,Y1,X2,Y2看作四条分界线,用四个线段树分别维护原序列上某一段区间的鱼的x/y坐标有没有超过分界线。

二、维护区间最大值。

三、如果当前区间最大值增加后未超过,打个lazy标记 r e t u r n return return,否则暴力找到那些超过了分界线的点,把点值改为极小值(相当于忽略该点)。

四、复杂度分析:由于每一个点会过线一次,所以这里是 O ( n l o g n ) O(nlogn) O(nlogn),有 4 4 4的常数.
总复杂度: O ( ( 2 ∗ m ∗ l o g n + 5 ∗ n ∗ l o g n ) ∗ T ) O((2*m*logn+5*n*logn)*T) O(2mlogn+5nlogn)T)

五、分块大法:分成根号n块,维护最大值,如果块内越界就重构(访问块内所有点,统计合法点数,重新更新最大值)好写,跑的还快。


CODE

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pf printf
inline int red()
{
    int data=0;int w=1; char ch=0;
    ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
#define in red() 
cs int N=3e4+10;
cs int long long inf=1e18;
int sum[N],n,x[N],y[N],qual[N];
#define lb(x) (x&(-x))
inline void change(int p,int k){for(;p<=n;p+=lb(p))sum[p]+=k;}
inline int query(int p){int ans=0;for(;p>=1;p-=lb(p))ans+=sum[p];return ans; } 
inline void check(int u); 
struct tre{
	#define lc (p<<1)
	#define rc ((p<<1)|1)
	long long mx[N<<2];
	int bord,kd,lazy[N<<2],kd2;
	bool flag[N];
	inline void pushup(int p){ mx[p]=max(mx[lc],mx[rc]);}
	inline void pushnow(int p,int dlt){
		lazy[p]+=dlt;
		mx[p]+=dlt;
	} 
	inline void pushdown(int p){
		if(lazy[p])pushnow(lc,lazy[p]),pushnow(rc,lazy[p]);
		lazy[p]=0;
	}
	inline void build(int p,int l,int r){
		lazy[p]=0;
		if(l==r){
			int vl=kd? y[l] : x[l];		
			mx[p]=vl;	 
			flag[l]=kd2?mx[p]<=bord:mx[p]<bord;
		 	return;
		}
		int mid=(l+r)>>1;
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(p);
	}
	inline void change(int p,int l,int r,int ql,int qr,int d){
		if(ql<=l&&r<=qr&&((kd2&&mx[p]+d<=bord)||(!kd2&&mx[p]+d<bord))){
			pushnow(p,d);
			return;
		}
		if(l==r){		
			pushnow(p,d);
			flag[l]=0;
			if(qual[l]^(-1))check(l);
			mx[p]=-inf; 
			return;
		}	
		pushdown(p); 
		int mid=(l+r)>>1;
		if(ql<=mid)change(lc,l,mid,ql,qr,d);
		if(qr>mid)change(rc,mid+1,r,ql,qr,d);
		pushup(p);
	}
	inline void init(int _bord,int _kd,int _kd2){
		bord=_bord;kd=_kd;kd2=_kd2;
	}
}tr[4];
inline void check(int u){
	bool f=(!tr[0].flag[u]&&tr[1].flag[u]&&!tr[2].flag[u]&&tr[3].flag[u]);
	if(!qual[u]&&f)change(u,1);
	if(qual[u]&&!f)change(u,-1);
	if(!tr[1].flag[u]||!tr[3].flag[u])qual[u]=-1;
	else qual[u]=f;
}
signed main(){
	int t;t=in;
	while(t--){
		n=in;
		int x_1,x_2,y_1,y_2;
		x_1=in;y_1=in;x_2=in;y_2=in;
		for(int i=1;i<=n;++i)x[i]=in,y[i]=in;
		tr[0].init(x_1,0,0);tr[1].init(x_2,0,1);
		tr[2].init(y_1,1,0);tr[3].init(y_2,1,1);
		memset(sum,0,sizeof sum);
		memset(qual,0,sizeof qual);
		for(int i=0;i<4;++i)tr[i].build(1,1,n);
		for(int i=1;i<=n;++i)check(i);
		int m=in;	
		while(m--){
			int f=in;
			int l=in,r=in,d;
			if(f==1){
				d=in;
				tr[1].change(1,1,n,l,r,d);
				tr[0].change(1,1,n,l,r,d);
			}
			if(f==2){
				d=in;
				tr[3].change(1,1,n,l,r,d);
				tr[2].change(1,1,n,l,r,d);
			}
			if(f==3){
				pf("%d\n",query(r)-query(l-1));
			}
		}
	}
	
	return 0;
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值