【HDU 5283】【JZOJ 4694】 火神的鱼
来源:互联网 发布:java网络高级编程 编辑:程序博客网 时间:2024/04/30 16:55
Description
火神最爱的就是吃鱼了,所以某一天他来到了一个池塘边捕鱼。池塘可以看成一个二维的平面,而他的渔网可以看成一个与坐标轴平行的矩形。
池塘里的鱼不停地在水中游动,可以看成一些点。有的时候会有鱼游进渔网,有的时候也会有鱼游出渔网。所以火神不知道什么时候收网才可以抓住最多的鱼,现在他寻求你的帮助。
他对池塘里的每条鱼都给予了一个标号,分别从1到n标号,n表示池塘里鱼的总数。鱼的游动可以概括为两个动作:
1 l r d : 表示标号在[l,r]这个区间内的鱼向x轴正方向游动了d个单位长度。
2 l r d:表示标号在[l,r]这个区间内的鱼向y轴正方向游动了d个单位长度。
在某些时刻火神会询问你现在有多少条他关心的鱼在渔网内(边界上的也算),请你来帮助他吧。
对于100%的数据1≤T≤10,1≤n,m≤30000,1≤l≤r≤n. 1≤d≤10^9,x1≤x2,y1≤y2。保证任意时刻所有涉及的坐标值在[−10^9,10^9]范围内。
Analysis
。。。
这题也是可以
。。。
留给我一些喘息时间
首先,我在两棵线段树打了一个build,3个query,3个modify,1个down,1个up,1个update。。。
每棵线段树里记录lazy标记,
打了1.5h,调了3.5h。。。。
从中暴露出一个巨大有用却容易忽视的问题:码力仍需加强,调试技术欠佳。
这道题有一个不起眼的细节却决定了此题的整个思考方向:鱼只可能往右或往上游。
又因为矩阵固定,所以鱼只要游出了矩阵就永远不可能游回来。
首先,先看x坐标。
先把区间的坐标全部加。
然后查看一下,有没有鱼游进了矩阵,有没有鱼游出了矩阵。进矩阵要满足两个坐标均位于矩阵内,若有,则更新答案,修改上面线段树记录的种种信息;出矩阵只要一个坐标出了就出了,同时可以永久地把该点删掉,修改线段树记录的种种信息。
查询直接查就可以了。
O(mlogn)
Code
#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)using namespace std;const int N=30010,INF=2147483647;int n,x1,y1,x2,y2,p1,p2,mp1,mp2,ans[N*4];struct fish{ int x,y;}a[N];struct segment{ int mx,mn,pmx,pmn,lz; //mn:rightest pos lefter than x1 //mx:rightest pos lefter than x2}tr[2][N*4];void update(segment &a,int z){ if(a.mx!=-INF) a.mx+=z; if(a.mn!=-INF) a.mn+=z; a.lz+=z;}void up(int p,int v){ if(tr[p][v+v].mn>tr[p][v+v+1].mn) tr[p][v].mn=tr[p][v+v].mn,tr[p][v].pmn=tr[p][v+v].pmn; else tr[p][v].mn=tr[p][v+v+1].mn,tr[p][v].pmn=tr[p][v+v+1].pmn; if(tr[p][v+v].mx>tr[p][v+v+1].mx) tr[p][v].mx=tr[p][v+v].mx,tr[p][v].pmx=tr[p][v+v].pmx; else tr[p][v].mx=tr[p][v+v+1].mx,tr[p][v].pmx=tr[p][v+v+1].pmx; ans[v]=ans[v+v]+ans[v+v+1];}void down(int p,int v){ if(!tr[p][v].lz) return; int z=tr[p][v].lz; update(tr[p][v+v],z); update(tr[p][v+v+1],z); tr[p][v].lz=0;}void build(int v,int l,int r){ if(l==r) { tr[0][v].pmn=tr[0][v].pmx=tr[1][v].pmn=tr[1][v].pmx=tr[0][v].lz=tr[1][v].lz=ans[v]=0; tr[0][v].mn=tr[0][v].mx=tr[1][v].mn=tr[1][v].mx=-INF; if(x1<=a[l].x && a[l].x<=x2 && y1<=a[l].y && a[l].y<=y2) ans[v]=1; if(a[l].x<x1) tr[0][v].mn=a[l].x,tr[0][v].pmn=l; if(x1<=a[l].x && a[l].x<=x2) tr[0][v].mx=a[l].x,tr[0][v].pmx=l; if(a[l].y<y1) tr[1][v].mn=a[l].y,tr[1][v].pmn=l; if(y1<=a[l].y && a[l].y<=y2) tr[1][v].mx=a[l].y,tr[1][v].pmx=l; return; } tr[0][v].lz=tr[1][v].lz=0; int mid=(l+r)>>1; build(v+v,l,mid); build(v+v+1,mid+1,r); up(0,v),up(1,v);}void change(int p,int v,int l,int r,int x,int y,int z){ if(l==x && r==y) { update(tr[p][v],z); return; } down(p,v); int mid=(l+r)>>1; if(y<=mid) change(p,v+v,l,mid,x,y,z); else if(x>mid) change(p,v+v+1,mid+1,r,x,y,z); else change(p,v+v,l,mid,x,mid,z),change(p,v+v+1,mid+1,r,mid+1,y,z); up(p,v);}void find(int p,int v,int l,int r,int x,int y){ if(l==x && r==y) { if(tr[p][v].mn>mp1) mp1=tr[p][v].mn,p1=tr[p][v].pmn; if(tr[p][v].mx>mp2) mp2=tr[p][v].mx,p2=tr[p][v].pmx; return; } down(p,v); int mid=(l+r)>>1; if(y<=mid) find(p,v+v,l,mid,x,y); else if(x>mid) find(p,v+v+1,mid+1,r,x,y); else find(p,v+v,l,mid,x,mid), find(p,v+v+1,mid+1,r,mid+1,y); up(p,v);}void clear(int p,int v,int l,int r,int x,bool bz){ if(l==r) { tr[p][v].mx=tr[p][v].mn,tr[p][v].pmx=tr[p][v].pmn,tr[p][v].mn=-INF,tr[p][v].pmn=0; if(bz) tr[p][v].mx=-INF,tr[p][v].pmx=0,ans[v]=0; return; } down(0,v),down(1,v); int mid=(l+r)>>1; if(x<=mid) clear(p,v+v,l,mid,x,bz); else clear(p,v+v+1,mid+1,r,x,bz); up(0,v),up(1,v);}void add(int p,int v,int l,int r,int x){ if(l==r) { tr[p][v].mx=tr[p][v].mn,tr[p][v].pmx=tr[p][v].pmn,tr[p][v].mn=-INF,tr[p][v].pmn=0; ans[v]=1; return; } down(0,v),down(1,v); int mid=(l+r)>>1; if(x<=mid) add(p,v+v,l,mid,x); else add(p,v+v+1,mid+1,r,x); up(0,v),up(1,v);}int query(int v,int l,int r,int x,int y){ if(l==x && r==y) return ans[v]; down(0,v),down(1,v); int mid=(l+r)>>1; if(y<=mid) return query(v+v,l,mid,x,y); else if(x>mid) return query(v+v+1,mid+1,r,x,y); else return query(v+v,l,mid,x,mid)+query(v+v+1,mid+1,r,mid+1,y); up(0,v),up(1,v);}bool serch(int p,int v,int l,int r,int x){ if(l==r) return tr[p][v].mn==-INF && tr[p][v].mx!=-INF; down(p,v); int mid=(l+r)>>1; if(x<=mid) return serch(p,v+v,l,mid,x); else return serch(p,v+v+1,mid+1,r,x); up(p,v);}void swim(int p,int l,int r,int z){ change(p,1,1,n,l,r,z); for(mp1=-INF,find(p,1,1,n,l,r);mp1>=(p?y1:x1);mp1=-INF,find(p,1,1,n,l,r)) { bool ok=serch(p^1,1,1,n,p1); if(ok) add(p,1,1,n,p1); else clear(p,1,1,n,p1,0); } for(mp2=-INF,find(p,1,1,n,l,r);mp2>(p?y2:x2);mp2=-INF,find(p,1,1,n,l,r)) clear(0,1,1,n,p2,1),clear(1,1,1,n,p2,1);}int main(){ int _,T,tp,l,r,z; scanf("%d",&T); while(T--) { scanf("%d %d %d %d %d",&n,&x1,&y1,&x2,&y2); fo(i,1,n) scanf("%d %d",&a[i].x,&a[i].y); build(1,1,n); scanf("%d",&_); fo(i,1,_) { scanf("%d %d %d",&tp,&l,&r); if(tp==1 || tp==2) { scanf("%d",&z); swim(tp-1,l,r,z); } else printf("%d\n",query(1,1,n,l,r)); } } return 0;}
0 1
- 【JZOJ 4694】【HDU 5283】火神的鱼
- 【HDU 5283】【JZOJ 4694】 火神的鱼
- JZOJ 4694 火神的鱼
- 【JZOJ 4693】疯狂的火神
- JZOJ.4694【NOIP2016提高A组模拟8.14】火神的鱼
- 【hdu5283】火神的鱼
- 火神的鱼
- 【HDU5283】【JZOJ4694】火神的鱼
- 【BestCoder Round #59 div.1 B】【JZOJ 4693】 疯狂的火神
- JZOJ.4693【NOIP2016提高A组模拟8.14】疯狂的火神
- JZOJ 4693 疯狂的火神【NOIP2016提高A组模拟8.14】
- 疯狂的火神题解
- 【JZOJ4693】疯狂的火神
- 【NOIP2016提高A组模拟8.14】火神的鱼
- [JZOJ4694] 火神的鱼 [HDU5283] Senior's Fish
- NOIPの模拟_2016_8_14_t2_疯狂的火神
- 【BestCoder Round #59 (div.1) B】【疯狂的火神】
- JZOJ4693. 【NOIP2016提高A组模拟8.14】疯狂的火神
- HDU 2710 Max Factor
- 知乎上遇到的对AOP的理解
- 转一篇心灵鸡汤,在贴吧上看的,作者不详
- 【HDU 2544 最短路】
- Cocos2d-x的学习 触碰事件老版本和新版本的对比 第四节
- 【HDU 5283】【JZOJ 4694】 火神的鱼
- 顺序栈和链式栈的理解与使用
- 【转】脉络清晰的BP神经网络讲解
- Java基础增强---枚举
- iOS 数据存储:Plist
- 链式存储结构即链式结构简单介绍
- BZOJ2160 拉拉队排练
- continue与break的区别
- Spring在代码中获取bean的几种方式