一个10^6行10^6列的网格图,上面有一些牛、花和一些矩形围栏,围栏在格子的边界上,牛和花在格子里,牛只能向下或向右走,牛也不能穿过围栏和地图边界,求每头牛它能到达的花的数量。注意栅栏不会相交

标签:
一道idea非常好的题
首先这题可以DP,不过转移之类的需要讨论,比较麻烦
$dp[i][j]=\begin{Bmatrix} 0(下面和右面都有栅栏)\\ dp[i+1][j](右面有栅栏)\\ dp[i][j+1](下面有栅栏)\\ dp[i+1][j]+dp[i][j+1]-dp[i+1][j+1]((i+1,j+1)不是栅栏的左上角)\\ dp[i+1][j]+dp[i][j+1]-dp[x+1][y+1]((i+1,j+1)是左上角,(x,y)是右下角)& & \end{Bmatrix}+flower[i][j]$
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();} while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();} return x*f; } #define MAXY 1000000 #define MAXF 200010 #define MAXN 200010 #define MAXM 200010 int F,M,N; struct FenceNode{int x1,x2,y1,y2;}fen[MAXF]; struct CowNode{int x,y,id;}cow[MAXN]; struct FlowerNode{int x,y;}flo[MAXM]; struct LineNode{int y,x1,x2,id,f;}line[MAXF<<1]; int tp; struct SegmentTreeNode{int l,r,tag,bk,sum;}tree[MAXY<<2]; int tmp[MAXF],ans[MAXN]; inline void Update(int now) { tree[now].bk=min(tree[now<<1].bk,tree[now<<1|1].bk); tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum; } inline void PushDown(int now) { if (!tree[now].tag || tree[now].l==tree[now].r) return; tree[now].tag=0; tree[now<<1].sum=0; tree[now<<1|1].sum=0; tree[now<<1].tag=1; tree[now<<1|1].tag=1; } inline void BuildTree(int now,int l,int r) { tree[now].l=l,tree[now].r=r; tree[now].sum=0; tree[now].tag=0; tree[now].bk=MAXY; if (l==r) return; int mid=(l+r)>>1; BuildTree(now<<1,l,mid); BuildTree(now<<1|1,mid+1,r); Update(now); } inline void PointChangeSum(int now,int pos,int D) { if (pos==MAXY+1 || pos==0) return; int l=tree[now].l,r=tree[now].r; PushDown(now); if (l==r) {tree[now].sum+=D; return;} int mid=(l+r)>>1; if (pos<=mid) PointChangeSum(now<<1,pos,D); if (pos>mid) PointChangeSum(now<<1|1,pos,D); Update(now); } inline void PointChangeBreak(int now,int pos,int D) { if (pos==MAXY+1 || pos==0) return; int l=tree[now].l,r=tree[now].r; PushDown(now); if (l==r) {tree[now].bk=D? l:MAXY; return;} int mid=(l+r)>>1; if (pos<=mid) PointChangeBreak(now<<1,pos,D); if (pos>mid) PointChangeBreak(now<<1|1,pos,D); Update(now); } inline void IntervalChange(int now,int L,int R) { if (L==0 || R==MAXY+1 || R<L) return; int l=tree[now].l,r=tree[now].r; PushDown(now); if (L<=l && R>=r) {tree[now].tag=1; tree[now].sum=0; return;} int mid=(l+r)>>1; if (L<=mid) IntervalChange(now<<1,L,R); if (R>mid) IntervalChange(now<<1|1,L,R); Update(now); } inline int IntervalQuerySum(int now,int L,int R) { if (L==0 || R==MAXY+1 || R<L) return 0; int l=tree[now].l,r=tree[now].r; PushDown(now); if (L<=l && R>=r) return tree[now].sum; int mid=(l+r)>>1,re=0; if (L<=mid) re+=IntervalQuerySum(now<<1,L,R); if (R>mid) re+=IntervalQuerySum(now<<1|1,L,R); return re; } inline int IntervalQueryBreak(int now,int L,int R) { if (L==0 || R==MAXY+1 || R<L) return 0; int l=tree[now].l,r=tree[now].r; PushDown(now); if (L<=l && R>=r) return tree[now].bk; int mid=(l+r)>>1,re=MAXY; if (L<=mid) re=min(re,IntervalQueryBreak(now<<1,L,R)); if (R>mid) re=min(re,IntervalQueryBreak(now<<1|1,L,R)); return re; } inline bool cmpLine(LineNode A,LineNode B) {return A.y!=B.y? A.y>B.y : A.x1<B.x1;} inline bool cmpCow(CowNode A,CowNode B) {return A.y>B.y;} inline bool cmpFlower(FlowerNode A,FlowerNode B) {return A.y>B.y;} int main() { F=read(); for (int i=1; i<=F; i++) fen[i].x1=read(),fen[i].y1=read(),fen[i].x2=read(),fen[i].y2=read(); for (int i=1; i<=F; i++) line[++tp]=(LineNode){fen[i].y1-1,fen[i].x1,fen[i].x2,i,-1}, line[++tp]=(LineNode){fen[i].y2,fen[i].x1,fen[i].x2,i,1}; sort(line+1,line+tp+1,cmpLine); M=read(); for (int i=1; i<=M; i++) flo[i].x=read(),flo[i].y=read(); sort(flo+1,flo+M+1,cmpFlower); N=read(); for (int i=1; i<=N; i++) cow[i].x=read(),cow[i].y=read(),cow[i].id=i; sort(cow+1,cow+N+1,cmpCow); BuildTree(1,1,MAXY); int nowl=1,nowf=1,nowc=1,next,sum; for (int i=MAXY; i; i--) { while (line[nowl].y==i) { if (line[nowl].f==-1) { IntervalChange(1,line[nowl].x1,line[nowl].x2); PointChangeSum(1,line[nowl].x1-1,-tmp[line[nowl].id]); PointChangeBreak(1,line[nowl].x1-1,0); PointChangeBreak(1,line[nowl].x2,0); } else { next=IntervalQueryBreak(1,line[nowl].x2,MAXY); sum=IntervalQuerySum(1,line[nowl].x1,line[nowl].x2); tmp[line[nowl].id]=IntervalQuerySum(1,line[nowl].x2+1,next); IntervalChange(1,line[nowl].x1,line[nowl].x2); PointChangeSum(1,line[nowl].x1-1,sum+tmp[line[nowl].id]); PointChangeBreak(1,line[nowl].x1-1,1); PointChangeBreak(1,line[nowl].x2,1); } nowl++; } while (flo[nowf].y==i) PointChangeSum(1,flo[nowf].x,1),nowf++; while (cow[nowc].y==i) next=IntervalQueryBreak(1,cow[nowc].x,MAXY), ans[cow[nowc].id]=IntervalQuerySum(1,cow[nowc].x,next), nowc++; } for (int i=1; i<=N; i++) printf("%d\n",ans[i]); return 0; }
【BZOJ-4422】Cow Confinement 线段树 + 扫描线 + 差分 (优化DP)
标签:
原文地址:http://www.cnblogs.com/DaD3zZ-Beyonder/p/5776608.html