天使玩偶:CDQ分治
这道好(du)题(liu)还是很不错的 挺锻炼代码能力和不断优化 卡常的能力的。
对于 每次询问 我都可以将其分出方向 然后 写 也就是针对于4个方向 左下 左上 右下 右上
这样的话 就成功转换了问题 求4次 三维偏序即可 水题啊。
然后 打完代码 就提交 T飞了
//#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<utility>
#include<queue>
#include<deque>
#include<vector>
#include<stack>
#include<algorithm>
#include<set>
#include<bitset>
#include<map>
#define INF 2147483646
#define ll long long
#define ldb long double
#define x(i) t[i].x
#define y(i) t[i].y
#define k(i) t[i].k
#define t(i) t[i].t
#define id(i) t[i].id
using namespace std;
char buf[<<],*ft,*fs;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
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;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar();return;
}
const int MAXN=,maxn=;
int n,m,tot,num,cnt;
struct wy
{
int x,y;
int t,k;
int id;
}t[MAXN<<],tmp[MAXN<<];
int ans[MAXN],c[maxn+];//树状数组维护前缀最大值!
//注意时间戳也得排序 我的思维漏洞!
int cmp(wy x,wy y)//左下
{
if(x.x==y.x&&x.y==x.y)return x.t<y.t;
return x.x==y.x?x.y<y.y:x.x<y.x;
}
int cmp1(wy x,wy y)//左上
{
if(x.x==y.x&&x.y==x.y)return x.t<y.t;
return x.x==y.x?x.y>y.y:x.x<y.x;
}
int cmp2(wy x,wy y)//右下
{
if(x.x==y.x&&x.y==x.y)return x.t<y.t;
return x.x==y.x?x.y<y.y:x.x>y.x;
}
int cmp3(wy x,wy y)//右上
{
if(x.x==y.x&&x.y==x.y)return x.t<y.t;
return x.x==y.x?x.y>y.y:x.x>y.x;
}
inline int max(int x,int y){return x>y?x:y;}
void add(int x,int y)
{
if(y==INF){for(;x<=maxn;x+=x&(-x))c[x]=-INF;return;}
for(;x<=maxn;x+=x&(-x))c[x]=max(c[x],y);
return;
}
inline int ask(int x)
{
int sum=-INF;
for(;x;x-=x&(-x))sum=max(sum,c[x]);
return sum;
}
void CDQ(int l,int r,int p)
{
if(l==r)return;
int mid=(l+r)>>;
CDQ(l,mid,p);
CDQ(mid+,r,p);
int i=l,j=mid+;
if(p==)
{
for(int k=l;k<=r;++k)
{
if(j>r||(i<=mid&&t(i)<=t(j)))
{
if(k(i)!=)add(y(i),x(i)+y(i));
tmp[k]=t[i];
++i;
}
else
{
if(k(j)==){tmp[k]=t[j];++j;continue;}
//if(id(j)==1)cout<<x(j)<<' '<<y(j)<<endl;
int maxx=ask(y(j));
if(maxx==-INF){tmp[k]=t[j];++j;continue;}
ans[id(j)]=min(ans[id(j)],y(j)+x(j)-maxx);
tmp[k]=t[j];
++j;
}
}
for(int k=l;k<=r;k++)
{
if(k<=mid&&k(k)!=)add(y(k),INF);
t[k]=tmp[k];
}
}
else
{
for(int k=l;k<=r;++k)
{
if(j>r||(i<=mid&&t(i)<=t(j)))
{
if(k(i)!=)add(maxn-y(i),x(i)-y(i));
tmp[k]=t[i];
++i;
}
else
{
if(k(j)==){tmp[k]=t[j];++j;continue;}
int maxx=ask(maxn-y(j));
if(maxx==-INF){tmp[k]=t[j];++j;continue;}
//cout<<maxx<<endl;
ans[id(j)]=min(ans[id(j)],x(j)-y(j)-maxx);
tmp[k]=t[j];
++j;
}
}
for(int k=l;k<=r;k++)
{
if(k<=mid&&k(k)!=)add(maxn-y(k),INF);
t[k]=tmp[k];
}
}
return;
}
void CDQ1(int l,int r,int p)
{
if(l==r)return;
int mid=(l+r)>>;
CDQ1(l,mid,p);
CDQ1(mid+,r,p);
int i=l,j=mid+;
if(p==)
{
for(int k=l;k<=r;++k)
{
if(j>r||(i<=mid&&t(i)<=t(j)))
{
if(k(i)!=)add(y(i),y(i)-x(i));
tmp[k]=t[i];
++i;
}
else
{
if(k(j)==){tmp[k]=t[j];++j;continue;}
//if(id(j)==1)cout<<x(j)<<' '<<y(j)<<endl;
int maxx=ask(y(j));
if(maxx==-INF){tmp[k]=t[j];++j;continue;}
ans[id(j)]=min(ans[id(j)],y(j)-x(j)-maxx);
tmp[k]=t[j];
++j;
}
}
for(int k=l;k<=r;k++)
{
if(k<=mid&&k(k)!=)add(y(k),INF);
t[k]=tmp[k];
}
}
else
{
for(int k=l;k<=r;++k)
{
if(j>r||(i<=mid&&t(i)<=t(j)))
{
if(k(i)!=)add(maxn-y(i),-x(i)-y(i));//此处不要想当然的写
tmp[k]=t[i];
++i;
}
else
{
if(k(j)==){tmp[k]=t[j];++j;continue;}
int maxx=ask(maxn-y(j));
if(maxx==-INF){tmp[k]=t[j];++j;continue;}
ans[id(j)]=min(ans[id(j)],-maxx-x(j)-y(j));//变形要正确啊!
tmp[k]=t[j];
++j;
}
}
for(int k=l;k<=r;k++)
{
if(k<=mid&&k(k)!=)add(maxn-y(k),INF);
t[k]=tmp[k];
}
}
return;
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
memset(ans,,sizeof(ans));
n=read();m=read();num=n;
for(int i=;i<=n;i++)x(i)=read(),y(i)=read();
for(int i=;i<=m;i++)
{
int p=read();
x(++num)=read();y(num)=read();
if(p==)k(num)=,id(num)=++cnt;
t(num)=++tot;
}
//for(int i=1;i<=num;i++)cout<<x(i)<<' '<<y(i)<<' '<<t(i)<<' '<<k(i)<<endl;
for(int i=;i<=maxn;i++)c[i]=-INF;
sort(t+,t++num,cmp);//左下
CDQ(,num,);//左下
//for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
for(int i=;i<=maxn;i++)c[i]=-INF;
sort(t+,t++num,cmp1);//左上
CDQ(,num,);//左上
//for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
for(int i=;i<=maxn;i++)c[i]=-INF;
sort(t+,t++num,cmp2);//右下
CDQ1(,num,);//右下
//for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
for(int i=;i<=maxn;i++)c[i]=-INF;
sort(t+,t++num,cmp3);//右上
CDQ1(,num,);//右上
//for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
for(int i=;i<=cnt;i++)put(ans[i]);
return ;
}
都别管我我要写4次CDQ 我要sort 4次然后不出意料只拿到50分。
原因是sort的次数多了 常数是别人的近乎4倍 (有的人一次sort都不做 按照时间直接排)
然后脑残的写了这么段代码 一直T 照着书上的 标程改了一下是一种比较简洁的做法。
但是其CDQ的每层都需要sort 一下比较浪费时间但是还是能拿到60分的 开O2 能A呢。
然后学了一下书上的做法 发现真心简单 代码复杂度 时间复杂度 空间复杂度包括常数都远远低于我
// luogu-judger-enable-o2
//#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<utility>
#include<queue>
#include<deque>
#include<vector>
#include<stack>
#include<algorithm>
#include<set>
#include<bitset>
#include<map>
#define INF 2147483646
#define ll long long
#define ldb long double
#define x(i) t[i].x
#define y(i) t[i].y
#define t(i) t[i].t
#define id(i) t[i].id
using namespace std;
char buf[<<],*ft,*fs;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
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;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar();return;
}
const int MAXN=,maxn=;
int n,m,cnt,num,tot,h;
int ans[MAXN],c[maxn],maxx;
struct wy
{
int x,y;
int t;
int id;
friend int operator <(const wy &a,const wy &b)
{
return a.x==b.x?a.y<b.y:a.x<b.x;//此时排序不用时间戳(经过实验
//考虑一次CDQ 分治 时间复杂度 ≈(n+m)*log(n+m)^3左右
}
}t[MAXN],tmp[MAXN];
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x>y?y:x;}
inline void add(int x,int y){for(;x<=maxx;x+=x&(-x))c[x]=max(c[x],y);}
inline int abs(int x){return x<?-x:x;}
inline int ask(int x)
{
int maxx1=-INF;
for(;x;x-=x&(-x))maxx1=max(maxx1,c[x]);
return maxx1;
}
inline void remove1(int x)
{
for(;x<=maxx;x+=x&(-x))c[x]=-INF;
return;
}
void calculate(int st,int en,int w,int kx,int ky)//属性
{
for(int i=st;i!=en;i+=w)
{
int yy=(ky==?tmp[i].y:maxx-tmp[i].y);
int sum=kx*tmp[i].x+ky*tmp[i].y;
if(tmp[i].t==)add(yy,sum);
else
{
int an=ask(yy);
if(an==-INF)continue;
ans[tmp[i].id]=min(ans[tmp[i].id],sum-an);
}
//if(tmp[i].id==2)cout<<sum<<' '<<ask(yy)<<endl;
}
for(int i=st;i!=en;i+=w)if(tmp[i].t==)remove1(ky==?tmp[i].y:maxx-tmp[i].y);
}
void CDQ(int l,int r)
{
int mid=(l+r)>>;
if(l<mid)CDQ(l,mid);
if(mid+<r)CDQ(mid+,r);
h=;
for(int i=l;i<=r;i++)if((i<=mid&&t[i].t==)||(i>mid&&t[i].t==))tmp[++h]=t[i];
sort(tmp+,tmp++h);
calculate(,h+,,,);//左下
calculate(,h+,,,-);//左上
calculate(h,,-,-,);//右下
calculate(h,,-,-,-);//右上
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
n=read();m=read();num=n;
for(int i=;i<=n;++i)
{
x(i)=read();
y(i)=read();
t(i)=;
maxx=max(maxx,y(i));
}
for(int i=;i<=m;++i)
{
t(++num)=read();
x(num)=read();
y(num)=read();
id(num)=t(num)==?++cnt:;
maxx=max(maxx,y(num));
}
//put(cnt);
++maxx;//巧妙一招
for(int i=;i<=maxx;++i)c[i]=-INF;
memset(ans,,sizeof(ans));
CDQ(,num);
for(int i=;i<=cnt;i++)put(ans[i]);
return ;
}
比较难受 因为这浪费了我很多的时间 然后最后还是T 开了O2 死T一个点(原因是 我是个NC啊。。。
开O2 过了不算什么我要不开O2 过
点开题解发现我的第一个代码的思想及其接近其 题解中跑的最快的。
所以发现可以不用sort 于是顺利不开O2 第一个代码顺利得到80分。
发现可以加一个优化是 能不加到树状数组里就不加 到需要的时候再加 还有一些卡常的东西
最终不开O2 直接A (一直T的那个点是因为下标为0 树状数组原地GG了。。。)
//#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<utility>
#include<queue>
#include<deque>
#include<vector>
#include<stack>
#include<algorithm>
#include<set>
#include<bitset>
#include<map>
#define INF 2147483646
#define ll long long
#define ldb long double
#define x(i) t[i].x
#define y(i) t[i].y
#define k(i) t[i].k
#define t(i) t[i].t
#define id(i) t[i].id
#define R register
using namespace std;
//char buf[1<<15],*ft,*fs;
//inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
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;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar();return;
}
const int maxn=;
int n,m,tot,num,cnt,maxx1,maxx2;
struct wy
{
int x,y;
int k,id;
inline bool operator <(const wy &w)const
{
return x<w.x;
}
}t[maxn],tmp[maxn],a[maxn];
int ans[maxn],c[maxn+];
inline int max(int x,int y){return x>y?x:y;}
inline void add(int x,int y)
{ for(;x<=maxx1;x+=x&(-x))
{
if(c[x]>y)break;
else c[x]=y;
}
return;
}
inline void remove1(int x)
{
for(;x<=maxx1;x+=x&(-x))if(c[x])c[x]=;
return;
}
inline int ask(int x)
{
int sum=-INF;
for(;x;x-=x&(-x))sum=max(sum,c[x]);
return sum;
}
inline void CDQ(int l,int r)
{
int mid=(l+r)>>;
if(l<mid)CDQ(l,mid);
if(r>mid+)CDQ(mid+,r);
R int i=l,j=mid+;
for(j=mid+;j<=r;j++)
{
if(k(j)==)
{
for(;i<=mid&&x(i)<=x(j);i++)
if(k(i)==)add(y(i),x(i)+y(i));
int maxx=ask(y(j));
maxx==?:ans[id(j)]=min(ans[id(j)],y(j)+x(j)-maxx); }
}
for(j=l;j<i;j++)if(k(j)==)remove1(y(j));
i=l,j=mid+;
for(R int k=l;k<=r;++k)
{
if(j>r||(i<=mid&&t[i]<t[j]))tmp[k]=t[i],++i;
else tmp[k]=t[j],++j;
}
for(R int k=l;k<=r;++k)t[k]=tmp[k];
return;
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
n=read();m=read();num=n;
for(R int i=;i<=n;++i){x(i)=read()+,y(i)=read()+;maxx1=max(maxx1,y(i));maxx2=max(maxx2,x(i));}
for(R int i=;i<=m;++i)
{
int p=read();
x(++num)=read()+;y(num)=read()+;
if(p==)k(num)=,id(num)=++cnt;
maxx1=max(maxx1,y(num));
maxx2=max(maxx2,x(num));
}
++maxx1;++maxx2;
for(R int i=;i<=cnt;++i)ans[i]=INF;
for(R int i=;i<=num;++i)a[i]=t[i];
CDQ(,num);//左下
for(R int i=;i<=num;++i)t[i]=a[i],y(i)=maxx1-y(i);
CDQ(,num);//左上
for(R int i=;i<=num;++i)t[i]=a[i],x(i)=maxx2-x(i);
CDQ(,num);//右下
for(R int i=;i<=num;++i)t[i]=a[i],x(i)=maxx2-x(i),y(i)=maxx1-y(i);
CDQ(,num);//右上
for(R int i=;i<=cnt;++i)put(ans[i]);
return ;
}
当然 为了能够完美的A掉这道题 我决定去学一个更强的东西 KD-tree.
然后在抄了20min代码后觉定放弃 尧神说没多大卵用。。。
所以这篇博文到此啦,关键是不断优化的思想 少开O2
天使玩偶:CDQ分治的更多相关文章
- [BZOJ2716] [Violet 3]天使玩偶(CDQ分治)
[BZOJ2716] [Violet 3]天使玩偶(CDQ分治) 题面 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里, ...
- BZOJ 2716: [Violet 3]天使玩偶( CDQ分治 + 树状数组 )
先cdq分治, 然后要处理点对答案的贡献, 可以以询问点为中心分成4个区域, 然后去掉绝对值(4种情况讨论), 用BIT维护就行了. --------------------------------- ...
- [bzoj] 2716 天使玩偶 || CDQ分治
原题 已知n个点有天使玩偶,有m次操作: 操作1:想起来某个位置有一个天使玩偶 操作2:询问离当前点最近的天使玩偶的曼哈顿距离 显然的CDQ问题,三维分别为时间,x轴,y轴. 但是这道题的问题在于最近 ...
- BZOJ 2716 Violet 3 天使玩偶 CDQ分治
题目大意:初始给定平面上的一个点集.提供两种操作: 1.将一个点增加点集 2.查询距离一个点最小的曼哈顿距离 K-D树是啥...不会写... 我仅仅会CDQ分治 对于一个询问,查询的点与这个点的位置关 ...
- 洛谷P4169 天使玩偶 CDQ分治
还是照着CDQ的思路来. 但是有一些改动: 要求4个方向的,但是可爱的CDQ分治只能求在自己一个角落方向上的.怎么办?旋转!做4次就好了. 统计的不是和,而是——max!理由如下: 设当前点是(x,y ...
- CH 4701 - 天使玩偶 - [CDQ分治]
题目链接:传送门 关于CDQ分治(参考李煜东<算法竞赛进阶指南>): 对于一系列操作,其中的任何一个询问操作,其结果必然等价于:初始值 + 此前所有的修改操作产生的影响. 假设共有 $m$ ...
- BZOJ.2716.[Violet3]天使玩偶(CDQ分治 坐标变换)
题目链接 考虑对于两个点a,b,距离为|x[a]-x[b]|+|y[a]-y[b]|,如果a在b的右上,那我们可以把绝对值去掉,即x[a]+y[a]-(x[b]+y[b]). 即我们要求满足x[b]& ...
- BZOJ 2716 [Violet 3]天使玩偶 (CDQ分治、树状数组)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2716 怎么KD树跑得都那么快啊..我写的CDQ分治被暴虐 做四遍CDQ分治,每次求一个 ...
- 洛谷P4169 [Violet]天使玩偶/SJY摆棋子(CDQ分治)
[Violet]天使玩偶/SJY摆棋子 题目传送门 解题思路 用CDQ分治开了氧气跑过. 将输入给的顺序作为第一维的时间,x为第二维,y为第三维.对于距离一个询问(ax,ay),将询问分为四块,左上, ...
随机推荐
- vue使用node的入门
1.安装cnpm npm install -g cnpm --registry=https://registry.npm.taobao.org 验证是否安装 cnpm -v 2.安装vue cnpm ...
- http://www.cnblogs.com/chenmeng0818/p/6370819.html
http://www.cnblogs.com/chenmeng0818/p/6370819.html js中的正则表达式入门 什么是正则表达式呢? 正则表达式(regular expression ...
- UIInterfaceOrientation over iOS6 (应用旋转屏幕)
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) { UIInterfaceOrientationUnknown = UIDeviceOrien ...
- 网络编程 -- RPC实现原理 -- RPC -- 迭代版本V1 -- 本地方法调用
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V1——RPC -- 本地方法调用:不通过网络 入门 1. RPCObjectProxy rpcObjectProxy = new RPCObjec ...
- offsetHeight,clientHeight,scrollHeight,offsetY等属性的理解
el.offsetHeight = height + padding + border(滚动条是在边框内的,自然也包括在内) el.clientHeight = 可视化看到的高度 (就是content ...
- 【Docker】容器操作(转)
来自:https://www.cnblogs.com/zydev/p/5803461.html 列出主机上的容器 列出正在运行的容器: docker ps 列出所有容器: docker ps - ...
- distri.lua线程间通信的设计
首先简单介绍下distri.lua中的线程设计方案. distri.lua提供一个API函数fork用于创建新的C线程,这个C线程运行独立的lua虚拟机,为了在各线程之间通信 每个线程都会创建一个ch ...
- NLP入门资料
<统计自然语言处理> 一些基础理论概念,涉及统计自然语言处理的基本概念.理论方法和新研究进展,内容包括形式语言与自动机及其在自然语言处理中的应用.语言模型.隐马尔可夫模型.语料库技术.汉语 ...
- Java NIO学习笔记---Channel
Java NIO 的核心组成部分: 1.Channels 2.Buffers 3.Selectors 我们首先来学习Channels(java.nio.channels): 通道 1)通道基础 通道( ...
- SVN创建分支主干策略
本篇目录 前言 SVN分支管理策略 VisualSVN Server TortoiseSVN客户端 Repository的创建 Check out trunk创建新项目MyProject trunk更 ...