火神的鱼

火神的鱼

题解

挺水的一道题

由于d是恒大于0的,所以我们知道鱼的x值与y值应该是递增的。而只有一条鱼它x所加的区间在\[x1-x,x2-x\]y所加的区间在\[y1-y,y2-y\]时才有可能使得这条鱼在渔网中,我们考虑如何维护鱼所加的操作。

我们可以先根据鱼的下标建一棵线段树,用来存储当前区间被那些操作所影响到。由于这是一个线段树的形式,一个操作只能在log_{n}个不相交的区间中出现。我们从根节点走到任意一个叶节点所经过的节点的路径上所有的操作就是所有对这个节点有影响的操作,无论是询问还是移动。

但是这样的操作是没有顺序的,无法维护每个询问的答案。

我们考虑每一个节点对哪些询问产生了贡献,肯定只有处在将它加到在渔网中的区间的操作区间中的询问有贡献。我们可以线段树维护所有询问。它的每个位置记录当前操作节点对当前访问到的鱼区间产生贡献的大小。明显,如果当前区间不在操作节点的区间内,其贡献为0,否则就为它的操作值。

如果到达鱼区间的叶子节点的话,操作节点的线段树上有且仅有对其产生贡献的操作。我们只需要对符合条件的区间中,满足条件的询问加上这个点的贡献即可。符合条件的区间,可以在线段树上二分找到,至于当前询问符不符合条件,可以用懒标记来维护。

时间复杂度O\left(nlog^2_{n} \right )的样子。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define MAXN 30005
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x7f7f7f7f;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int t,m,n,ans[MAXN],stak;
struct tree{LL x,y;int lzy,sum;bool ta;}tr[MAXN<<2];
struct query{int opt,id;LL d;};
vector<query>Ask[MAXN<<2];
struct point{LL x,y;}le,ri,f[MAXN];
void Insert(int rt,int l,int r,int al,int ar,query aw){
	if(l>r||l>ar||r<al)return ;int mid=l+r>>1;
	if(al<=l&&r<=ar){Ask[rt].push_back(aw);return ;}
	if(al<=mid)Insert(rt<<1,l,mid,al,ar,aw);
	if(ar>mid)Insert(rt<<1|1,mid+1,r,al,ar,aw);
}
void pushdown(int rt){
	if(tr[rt].lzy){
		tr[rt<<1].lzy+=tr[rt].lzy;
		tr[rt<<1|1].lzy+=tr[rt].lzy;
		if(tr[rt<<1].ta)tr[rt<<1].sum+=tr[rt].lzy;
		if(tr[rt<<1|1].ta)tr[rt<<1|1].sum+=tr[rt].lzy;
		tr[rt].lzy=0;
	}
}
void insertx(int rt,int l,int r,int ai,LL aw){
	if(l>r||l>ai||r<ai)return ;
	if(l==r){tr[rt].x=aw;return ;}
	int mid=l+r>>1;pushdown(rt);
	if(ai<=mid)insertx(rt<<1,l,mid,ai,aw);
	if(ai>mid)insertx(rt<<1|1,mid+1,r,ai,aw);
	tr[rt].x=tr[rt<<1].x+tr[rt<<1|1].x;
}
void inserty(int rt,int l,int r,int ai,LL aw){
	if(l>r||l>ai||r<ai)return ;
	if(l==r){tr[rt].y=aw;return ;}
	int mid=l+r>>1;pushdown(rt);
	if(ai<=mid)inserty(rt<<1,l,mid,ai,aw);
	if(ai>mid)inserty(rt<<1|1,mid+1,r,ai,aw);
	tr[rt].y=tr[rt<<1].y+tr[rt<<1|1].y;
}
void insertt(int rt,int l,int r,int ai,bool aw){
	if(l>r||l>ai||r<ai)return ;
	if(l==r){tr[rt].ta=aw;return ;}
	int mid=l+r>>1;pushdown(rt);
	if(ai<=mid)insertt(rt<<1,l,mid,ai,aw);
	if(ai>mid)insertt(rt<<1|1,mid+1,r,ai,aw);
}
int queryx(int rt,int l,int r,int k){
	if(l==r)return l;int mid=l+r>>1;pushdown(rt);
	if(tr[rt<<1].x>=k)return queryx(rt<<1,l,mid,k);
	return queryx(rt<<1|1,mid+1,r,k-tr[rt<<1].x);
}
int queryy(int rt,int l,int r,int k){
	if(l==r)return l;int mid=l+r>>1;pushdown(rt);
	//printf("queryy %d %d %d %d %d\n",l,r,k,tr[rt<<1].y,tr[rt<<1|1].y); 
	if(tr[rt<<1].y>=k)return queryy(rt<<1,l,mid,k);
	return queryy(rt<<1|1,mid+1,r,k-tr[rt<<1].y);
}
void Putin(int rt){
	int siz=Ask[rt].size();
	for(int i=0;i<siz;i++){
		//printf("PutIn%d\n",Ask[rt][i].id);
		if(Ask[rt][i].opt==1)insertx(1,1,m,Ask[rt][i].id,Ask[rt][i].d);
		if(Ask[rt][i].opt==2)inserty(1,1,m,Ask[rt][i].id,Ask[rt][i].d);
		if(Ask[rt][i].opt==3)insertt(1,1,m,Ask[rt][i].id,1);
	}
}
void Putout(int rt){
	int siz=Ask[rt].size();
	for(int i=0;i<siz;i++){
		//printf("PutOut%d\n",Ask[rt][i].id);
		if(Ask[rt][i].opt==1)insertx(1,1,m,Ask[rt][i].id,0);
		if(Ask[rt][i].opt==2)inserty(1,1,m,Ask[rt][i].id,0);
		if(Ask[rt][i].opt==3)insertt(1,1,m,Ask[rt][i].id,0);
	}
	Ask[rt].clear();
}
void modify(int rt,int l,int r,int al,int ar,int aw){
	if(l>r||l>ar||r<al)return ;
	if(al<=l&&r<=ar){
		if(tr[rt].ta)tr[rt].sum+=aw;
		tr[rt].lzy+=aw;return ;
	}
	int mid=l+r>>1;pushdown(rt);
	if(al<=mid)modify(rt<<1,l,mid,al,ar,aw);
	if(ar>mid)modify(rt<<1|1,mid+1,r,al,ar,aw);
}
void Search(int rt,int l,int r){
	if(l>r)return ;//printf("toPUT %d %d\n",l,r);
	Putin(rt);
	if(l==r){
		int al=max(queryx(1,1,m,le.x-f[l].x),queryy(1,1,m,le.y-f[l].y));
		int ar=min(queryx(1,1,m,ri.x-f[l].x+1LL)-1,queryy(1,1,m,ri.y-f[l].y+1LL)-1);
		//printf("Search%d:%d %d\n",l,al,ar);
		if(al>ar){Putout(rt);return ;}
		//printf("%d add on %d %d %d\n",l,al,ar,ri.y-f[l].y+1LL);
		modify(1,1,m,al,ar,1);Putout(rt);return ;
	}
	int mid=l+r>>1;
	Search(rt<<1,l,mid);
	Search(rt<<1|1,mid+1,r);
	Putout(rt);
}
int getAns(int rt,int l,int r,int ai){
	if(l>r)return 0;if(l==r)return tr[rt].sum;
	int mid=l+r>>1;pushdown(rt);
	if(mid>=ai)return getAns(rt<<1,l,mid,ai);
	return getAns(rt<<1|1,mid+1,r,ai);
}
void build(int rt,int l,int r){
	tr[rt].sum=tr[rt].lzy=tr[rt].x=tr[rt].y=tr[rt].ta=0;
	if(l==r)return ;int mid=l+r>>1;
	build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
}
signed main(){
	freopen("fish.in","r",stdin);
	freopen("fish.out","w",stdout);
	read(t);
	while(t--){
		read(n);read(le.x);read(le.y);read(ri.x);read(ri.y);
		for(int i=1;i<=n;i++)read(f[i].x),read(f[i].y);
		read(m);m++;build(1,1,m);stak=0;
		for(int i=1;i<m;i++){
			query x;int l,r;read(x.opt);x.id=i;
			read(l);read(r);if(x.opt!=3)read(x.d);
			Insert(1,1,n,l,r,x);
			if(x.opt==3)ans[++stak]=i;
		}
		insertx(1,1,m,m,INF);inserty(1,1,m,m,INF);Search(1,1,n);
		for(int i=1;i<=stak;i++)printf("%d\n",getAns(1,1,m,ans[i]));
	}
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值