【BZOJ-4422】Cow Confinement 线段树 + 扫描线 + 差分 (优化DP)
4422: [Cerc2015]Cow Confinement
Time Limit: 50 Sec Memory Limit: 512 MB
Submit: 61 Solved: 26
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
2 2 8 4
1 9 4 10
6 7 9 9
3 3 7 3
9
3 4
8 4
11 5
10 7
10 8
9 8
2 8
4 11
9 11
8
1 1
5 10
6 9
3 7
7 1
4 2
7 5
3 3
Sample Output
1
0
1
3
1
3
0
HINT
Source
Solution
一道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]$
这样DP的时间复杂度是$O((N+F+M)^{2})$的
那么考虑优化这个DP
差分出$f[i][j]$表示$(i,j)$能得到,但$(i,j-1)$不能得到的花的数量
那么考虑扫描线,从右往左
那讨论一下各种情况,
遇到花单点数值+1;遇到一个未出现过的栅栏,区间查询和,单点修改数值,区间修改覆盖0;删除一个栅栏,区间修改覆盖0;遇见一头牛,找到下方第一个栅栏,区间求和;
显然都可以用线段树维护
查找下方第一个栅栏?维护一个最小即可
时间复杂度是$O(10^{6}log10^{6})$
实现起来有一些细节,线段树中需要加特判,当所需要修改的坐标为0啊之类的
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; 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<<]; int tp;
struct SegmentTreeNode{int l,r,tag,bk,sum;}tree[MAXY<<];
int tmp[MAXF],ans[MAXN];
inline void Update(int now)
{
tree[now].bk=min(tree[now<<].bk,tree[now<<|].bk);
tree[now].sum=tree[now<<].sum+tree[now<<|].sum;
}
inline void PushDown(int now)
{
if (!tree[now].tag || tree[now].l==tree[now].r) return;
tree[now].tag=;
tree[now<<].sum=; tree[now<<|].sum=;
tree[now<<].tag=; tree[now<<|].tag=;
}
inline void BuildTree(int now,int l,int r)
{
tree[now].l=l,tree[now].r=r;
tree[now].sum=; tree[now].tag=; tree[now].bk=MAXY;
if (l==r) return;
int mid=(l+r)>>;
BuildTree(now<<,l,mid);
BuildTree(now<<|,mid+,r);
Update(now);
}
inline void PointChangeSum(int now,int pos,int D)
{
if (pos==MAXY+ || pos==) return;
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (l==r) {tree[now].sum+=D; return;}
int mid=(l+r)>>;
if (pos<=mid) PointChangeSum(now<<,pos,D);
if (pos>mid) PointChangeSum(now<<|,pos,D);
Update(now);
}
inline void PointChangeBreak(int now,int pos,int D)
{
if (pos==MAXY+ || pos==) 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)>>;
if (pos<=mid) PointChangeBreak(now<<,pos,D);
if (pos>mid) PointChangeBreak(now<<|,pos,D);
Update(now);
}
inline void IntervalChange(int now,int L,int R)
{
if (L== || R==MAXY+ || R<L) return;
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) {tree[now].tag=; tree[now].sum=; return;}
int mid=(l+r)>>;
if (L<=mid) IntervalChange(now<<,L,R);
if (R>mid) IntervalChange(now<<|,L,R);
Update(now);
}
inline int IntervalQuerySum(int now,int L,int R)
{
if (L== || R==MAXY+ || R<L) return ;
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) return tree[now].sum;
int mid=(l+r)>>,re=;
if (L<=mid) re+=IntervalQuerySum(now<<,L,R);
if (R>mid) re+=IntervalQuerySum(now<<|,L,R);
return re;
}
inline int IntervalQueryBreak(int now,int L,int R)
{
if (L== || R==MAXY+ || R<L) return ;
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) return tree[now].bk;
int mid=(l+r)>>,re=MAXY;
if (L<=mid) re=min(re,IntervalQueryBreak(now<<,L,R));
if (R>mid) re=min(re,IntervalQueryBreak(now<<|,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=; i<=F; i++) fen[i].x1=read(),fen[i].y1=read(),fen[i].x2=read(),fen[i].y2=read();
for (int i=; i<=F; i++)
line[++tp]=(LineNode){fen[i].y1-,fen[i].x1,fen[i].x2,i,-},
line[++tp]=(LineNode){fen[i].y2,fen[i].x1,fen[i].x2,i,};
sort(line+,line+tp+,cmpLine);
M=read();
for (int i=; i<=M; i++) flo[i].x=read(),flo[i].y=read();
sort(flo+,flo+M+,cmpFlower);
N=read();
for (int i=; i<=N; i++) cow[i].x=read(),cow[i].y=read(),cow[i].id=i;
sort(cow+,cow+N+,cmpCow);
BuildTree(,,MAXY);
int nowl=,nowf=,nowc=,next,sum;
for (int i=MAXY; i; i--)
{
while (line[nowl].y==i)
{
if (line[nowl].f==-)
{
IntervalChange(,line[nowl].x1,line[nowl].x2);
PointChangeSum(,line[nowl].x1-,-tmp[line[nowl].id]);
PointChangeBreak(,line[nowl].x1-,);
PointChangeBreak(,line[nowl].x2,);
}
else
{
next=IntervalQueryBreak(,line[nowl].x2,MAXY);
sum=IntervalQuerySum(,line[nowl].x1,line[nowl].x2);
tmp[line[nowl].id]=IntervalQuerySum(,line[nowl].x2+,next);
IntervalChange(,line[nowl].x1,line[nowl].x2);
PointChangeSum(,line[nowl].x1-,sum+tmp[line[nowl].id]);
PointChangeBreak(,line[nowl].x1-,);
PointChangeBreak(,line[nowl].x2,);
}
nowl++;
}
while (flo[nowf].y==i)
PointChangeSum(,flo[nowf].x,),nowf++;
while (cow[nowc].y==i)
next=IntervalQueryBreak(,cow[nowc].x,MAXY),
ans[cow[nowc].id]=IntervalQuerySum(,cow[nowc].x,next),
nowc++;
}
for (int i=; i<=N; i++) printf("%d\n",ans[i]);
return ;
}
#include<cstdio>
#include<iostream>
using namespace std;
#include<cstring>
#include<cmath>
#include<algorithm>
const int X=1e6+,Y=1e6,F=2e5+,M=2e5+,N=2e5+;
char * cp=(char *)malloc();
void in(int &x){
while(*cp<''||*cp>'')++cp;
for(x=;*cp>=''&&*cp<='';)x=x*+(*cp++^'');
} struct FenS{
int xl,xr;
int y;
int i;
bool flag;
bool operator < (const FenS & o)const{
return y!=o.y?y>o.y:xl<o.xl;
}
}fence[F<<];
int fsum[F];
struct FloS{
int x,y;
bool operator < (const FloS & o)const{
return y>o.y;
}
}flower[M];
struct CS{
int x,y;
int i;
bool operator < (const CS & o)const{
return y>o.y;
}
}cow[N];
int ans[N]; struct SS{
int cnt;
bool cover;
bool barrier;
}segt[X<<];
#define lson node<<1,l,l+r>>1
#define rson node<<1|1,(l+r>>1)+1,r
void out(int node,int l,int r){
printf("segt[%d][%d,%d]={cnt=%d,cover=%d,barrier=%d}\n",node,l,r,segt[node].cnt,segt[node].cover,segt[node].barrier);
}
void pushup(int node){
segt[node].cnt=segt[node<<].cnt+segt[node<<|].cnt;
segt[node].barrier=segt[node<<].barrier|segt[node<<|].barrier;
}
void paint(int node){
//printf("paint(%d)\n",node);
segt[node].cover=;
segt[node].cnt=;
}
void pushdown(int node){
if(segt[node].cover){
paint(node<<),paint(node<<|);
segt[node].cover=;
}
}
void add(int node,int l,int r,int x,int delta){
//printf("add(%d,%d,%d,%d,%d)\n",node,l,r,x,delta);
//out(node,l,r);
segt[node].cnt+=delta;
if(l!=r){
pushdown(node);
if(x<=l+r>>)add(lson,x,delta);
else add(rson,x,delta);
pushup(node);
}
//printf("add:");
//out(node,l,r);
}
void cover(int node,int l,int r,int L,int R){
//out(node,l,r);
if(L<=l&&r<=R)paint(node);
else{
pushdown(node);
if(L<=l+r>>)cover(lson,L,R);
if(R>l+r>>)cover(rson,L,R);
pushup(node);
}
}
int query_cnt(int node,int l,int r,int L,int R){
//printf("query(%d,%d,%d,%d,%d)\n",node,l,r,L,R);
if(L<=l&&r<=R){
//printf("query_cnt get [%d][%d,%d]=%d\n",node,l,r,segt[node].cnt);
return segt[node].cnt;
}
else{
pushdown(node);
int ans=;
if(L<=l+r>>)ans+=query_cnt(lson,L,R);
if(R>l+r>>)ans+=query_cnt(rson,L,R);
return ans;
}
}
void update(int node,int l,int r,int x){
if(l==r)segt[node].barrier^=;
else{
pushdown(node);
if(x<=l+r>>)update(lson,x);
else update(rson,x);
pushup(node);
}
//printf("update:");
//out(node,l,r);
}
int query_barrier(int node,int l,int r,int L){
if(l>=L){
//printf("Query_barrier Get ");
//out(node,l,r);
if(segt[node].barrier){
while(l!=r)
if(segt[node<<].barrier)node<<=,r=l+r>>;
else node=node<<|,l=(l+r>>)+;
return l;
}
else return ;
}
else{
int tmp;
pushdown(node);
if(L<=l+r>>&&(tmp=query_barrier(lson,L)))return tmp;
else return query_barrier(rson,L);
}
}
int main(){
freopen("cow.in","r",stdin);
freopen("cow.out","w",stdout);
fread(cp,,,stdin);
int f;
in(f);
int x1,y1,x2,y2;
for(int i=f;i--;){
in(x1),in(y1),in(x2),in(y2);
fence[i<<]=(FenS){x1,x2,y1-,i,};
fence[i<<|]=(FenS){x1,x2,y2,i,};
}
sort(fence,fence+(f<<));
int m;
in(m);
for(int i=m;i--;)in(flower[i].x),in(flower[i].y);
sort(flower,flower+m);
int n;
in(n);
for(int i=;i<n;++i){
in(cow[i].x),in(cow[i].y);
cow[i].i=i;
}
sort(cow,cow+n); f=m=n=;
update(,,Y,Y);
int sum,br;
for(int i=Y;i;--i){
//printf("----%d----\n",i);
for(;fence[f].y==i;++f)
if(fence[f].flag==){
cover(,,Y,fence[f].xl,fence[f].xr);
if(fence[f].xl!=)add(,,Y,fence[f].xl-,-fsum[fence[f].i]); if(fence[f].xl!=)update(,,Y,fence[f].xl-);
if(fence[f].xr!=Y)update(,,Y,fence[f].xr);
}
else{
br=query_barrier(,,Y,fence[f].xr);
sum=query_cnt(,,Y,fence[f].xl,fence[f].xr);
fsum[fence[f].i]=query_cnt(,,Y,fence[f].xr+,br);
cover(,,Y,fence[f].xl,fence[f].xr);
if(fence[f].xl>)add(,,Y,fence[f].xl-,sum+fsum[fence[f].i]); if(fence[f].xl!=)update(,,Y,fence[f].xl-);
if(fence[f].xr!=Y)update(,,Y,fence[f].xr);
}
for(;flower[m].y==i;++m){
//cout<<flower[m].x<<","<<flower[m].y<<endl;
add(,,Y,flower[m].x,);
}
for(;cow[n].y==i;++n){
br=query_barrier(,,Y,cow[n].x);
//printf("br(%d)=%d\n",cow[n].x,br);
ans[cow[n].i]=query_cnt(,,Y,cow[n].x,br);
//printf("query(%d,%d)=%d\n",cow[n].x,br,ans[cow[n].i]);
}
} for(int i=;i<n;++i)printf("%d\n",ans[i]);
}
TA爷的代码
TA爷的模拟赛.....暴力都没写.....有点对不起TA爷....(不过似乎当时这题没得分的?)
自己的代码比较丑,这里附上当时TA爷的std,供参考
【BZOJ-4422】Cow Confinement 线段树 + 扫描线 + 差分 (优化DP)的更多相关文章
- BZOJ 4422 Cow Confinement (线段树、DP、扫描线、差分)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4422 我真服了..这题我能调一天半,最后还是对拍拍出来的...脑子还是有病啊 题解: ...
- 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)
D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...
- 线段树区间合并优化dp——cf1197E(好)
线段树优化dp的常见套路题,就是先按某个参数排序,然后按这个下标建立线段树,再去优化dp 本题由于要维护两个数据:最小值和对应的方案数,所以用线段树区间合并 /* dp[i]表示第i个套娃作为最内层的 ...
- bzoj 2131 : 免费的馅饼 (树状数组优化dp)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2131 思路: 题目给出了每个馅饼的下落时间t,和位置p,以及价值v,我们可以得到如下状态 ...
- [BZOJ 4771]七彩树(可持久化线段树+树上差分)
[BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...
- BZOJ 1818 线段树+扫描线
思路: 可以把题目转化成 给你一些沿坐标轴方向的线段 让你求交点个数 然后就线段树+扫描线 搞一搞 (线段不包含断点 最后+n 这种方式 比线段包含断点+各种特判要好写得多) //By SiriusR ...
- Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)
题目链接:http://codeforces.com/contest/522/problem/D 题目大意: 给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...
- 【POJ-2482】Stars in your window 线段树 + 扫描线
Stars in Your Window Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11706 Accepted: ...
- HDU 4419 Colourful Rectangle --离散化+线段树扫描线
题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...
随机推荐
- python执行linux shell管道输出内容
干净不留痕,用过都说好. echo "print 1+1" |python
- noi题库(noi.openjudge.cn) 1.8编程基础之多维数组T21——T25
T21 二维数组右上左下遍历 描述 给定一个row行col列的整数数组array,要求从array[0][0]元素开始,按从左上到右下的对角线顺序遍历整个数组. 输入 输入的第一行上有两个整数,依次为 ...
- tkinter 类继承的三种方式
tkinter class继承有三种方式. 提醒注意这几种继承的运行方式 一.继承 object 1.铺tk.Frame给parent: 说明: self.rootframe = tk.Frame(p ...
- 想请问下PDF双面打印时(打印机自动双面打印)为什么反面那页的内容是倒过来的,应该怎么设置?
用foxit reader 打印pdf 直接设置为双面打印并且一张2页打印,发现正反面刚好倒着来的,其实说的正反面倒着是从左右翻的角度来讲的,如果上下翻会发现刚好是这个顺序的,这个是要在双面打印设置里 ...
- 2013级软件工程GitHub账号信息
GitHub账号信息 序号 班级 学号 姓名 个人GitHub网址 1 信1301-1班 20122951 刘伟 https://github.com/weige8882 2 信1301-1班 201 ...
- PHP 依赖注入,从此不再考虑加载顺序
说这个话题之前先讲一个比较高端的思想--'依赖倒置原则' "依赖倒置是一种软件设计思想,在传统软件中,上层代码依赖于下层代码,当下层代码有所改动时,上层代码也要相应进行改动,因此维护成本较高 ...
- angular一些冷门的用法
1.controller的第三个参数
- [BZOJ1061][Noi 2008]志愿者招募(网络流)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1061 分析: 神题不解释,只能欣赏:https://www.byvoid.com/bl ...
- 后缀树(BZOJ3238TLE)
#include<cstdio> #include<cstring> #define LL long long ],stt[]; LL ans; ,sidcnt,lastcre ...
- TrueSkill 原理及实现
在电子竞技游戏中,特别是当有多名选手参加比赛的时候需要平衡队伍间的水平,让游戏比赛更加有意思.这样的一个参赛选手能力平衡系统通常包含以下三个模块: 一个包含跟踪所有玩家比赛结果,记录玩家能力的模块. ...