HDU - 6183 暴力,线段树动态开点,cdq分治
B - Color itHDU - 6183
题目大意:有三种操作,0是清空所有点,1是给点(x,y)涂上颜色c,2是查询满足1<=a<=x,y1<=b<=y2的(a,b)点一共有几种不同的颜色
一开始做的时候直接就是开51个vector保存每个颜色相应的点,然后就是询问就是,暴力循环判断这个颜色存不存在一个满足条件的点,感觉最差情况下应该会超时,不过却过了
#include<cstdio>
#include<vector>
using namespace std;
struct Node{
int x,y;
Node(){}
Node(int x,int y):x(x),y(y){}
};
vector<Node> c[];
int main()
{
int op,x,y,y1,cc;
while(scanf("%d",&op)&&op!=)
{
if(op==)
{
for(int i=;i<=;i++)
c[i].clear();
}
else if(op==)
{
scanf("%d%d%d",&x,&y,&cc);
c[cc].push_back(Node(x,y));
}
else
{
scanf("%d%d%d",&x,&y,&y1);
int ans=;
for(int i=;i<=;i++)
{
for(int j=;j<c[i].size();j++)
if(c[i][j].x<=x&&c[i][j].y>=y&&c[i][j].y<=y1)
{
ans++;
break;
}
}
printf("%d\n",ans);
}
}
return ;
}
暴力过一切
然后看网上有是线段树动态开点的做法,但实际上并不比上面暴力的写法快,反而慢上几十ms,不过可以当做一个算法扩展来联系。
首先1操作肯定就是单点更新了,而2操作上已经限定了x的左边为1,所以我们以y轴来建线段树维护个区间内x的最小值,那么2操作就是区间查询了。但我们知道正常静态的线段树需要4*SIZE的节点空间来保存信息的,在这里又需要51颗线段树,也就是51*4*1000000的空间来保存节点信息,不知道你们电脑能不能开那么大的数组,反正我的电脑和OJ的虚拟机是不行的。但其实最多150000个1操作和2操作,并不需要那么大的空间。所以这时候需要用到线段树的动态开点了。
静态的线段树,每个编号为x的节点,它的左孩子编号就为2*x,右孩子编号就为2*x+1,然后这个节点x,我们是保存它的区间L,R和其他一系列信息。而动态开点的话,对于编号为x的节点,它的左右孩子的编号就不一定是2*x和2*x+1的关系了,所以我们要保存下的是它的左右孩子的编号已经一系列相关的信息,然后对于每个节点就是当需要到它时再开辟它。其他操作就和静态的线段树差不多。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=;
struct Tree{
int lson,rson,minx;
}T[N];
int tn,flag,root[];
//root就保存这个颜色对于的那棵线段树的根节点编号
void init()
{
tn=;
for(int i=;i<=;i++)
root[i]=;
}
void updata(int &id,int L,int R,int y,int x)//在这里用L,R来表示节点id的区间
{
if(!id)
{//需要到这个节点了,开辟这个节点
id=tn++;
T[id].minx=N;
T[id].lson=T[id].rson=;//它的子节点还未用得上
}
T[id].minx=min(T[id].minx,x);//更新最小的x值
//下面就是线段树的单点修改
if(L==R)
return ;
int mid=(L+R)>>;
if(y<=mid)
updata(T[id].lson,L,mid,y,x);
else
updata(T[id].rson,mid+,R,y,x);
}
void query(int id,int L,int R,int l,int r,int x)
{
if(flag||!id)//如果已经有点满足条件,或者这个节点没开辟就返回
return ;
if(l<=L&&r>=R)
{
if(T[id].minx<=x)
flag=;//在y1和y2范围内有个x满足条件
return ;
}
int mid=(L+R)>>;
if(l<=mid)
query(T[id].lson,L,mid,l,r,x);
if(r>mid)
query(T[id].rson,mid+,R,l,r,x);
}
int main()
{
int op,x,y,y2,c;
init();
while(~scanf("%d",&op)&&op!=)
{
if(op==)
init();
else if(op==)
{
scanf("%d%d%d",&x,&y,&c);
updata(root[c],,,y,x);
}
else
{
scanf("%d%d%d",&x,&y,&y2);
int ans=;
for(int i=;i<=;i++)
{
flag=;
query(root[i],,,y,y2,x);
ans+=flag;
}
printf("%d\n",ans);
}
}
return ;
}
线段树下线段果
正解是cdq分治,待我学成归来,再更新。。。我回来了
cdq分治处理的话,就是三维偏序的一个处理,(操作时间,x轴,y轴),然后第一维已经有序,那么我们cdq分治处理第二维,然后线段树处理第三维。因为最多是50种颜色,那么我们采用状压的策略,把每个颜色C用2C来表示,然后线段树维护个区间或和。需要注意的就是y轴离散化下,不然容易超时。
#include<cstdio>
#include<algorithm>
#include<vector>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define M(x) ((T[x].l+T[x].r)>>1)
using namespace std;
typedef long long ll;
const int N=,Y=;
struct Tree{
int l,r;
ll val;
}T[Y];
struct Nop{
int op,x,y,y1;
ll val;//op1更新操作的val记录2^C,op2查询操作记录答案编号
friend bool operator <(const Nop &n1,const Nop &n2){
return n1.x==n2.x ? n1.op<n2.op : n1.x<n2.x;
}
}P[N<<],temp[N<<];
int pn=,qn=,newy[Y];
bool num[Y]={};
vector<int> vy;
ll ans[N]={},cf2[]={};
inline void addp(int op,int x,int y,int y1,ll val){
P[pn++]=(Nop){op,x,y,y1,val};
}
inline void addy(int y)
{
if(!num[y])
{
num[y]=;
vy.push_back(y);
}
}
void built(int id,int l,int r)
{
T[id].val=;
T[id].l=l,T[id].r=r;
if(l==r)
return ;
built(L(id),l,M(id));
built(R(id),M(id)+,r);
}
//线段树单点修改
void updata(int id,int pos,ll val)
{
if(T[id].l==T[id].r&&T[id].l==pos)
{
if(val)
T[id].val|=val;
else
T[id].val=;
return ;
}
if(pos<=M(id))
updata(L(id),pos,val);
else
updata(R(id),pos,val);
T[id].val=T[L(id)].val|T[R(id)].val;
}
//区间或和查询
ll query(int id,int l,int r)
{
ll ans=;
if(l<=T[id].l&&T[id].r<=r)
return T[id].val;
if(l<=M(id))
ans|=query(L(id),l,r);
if(r>M(id))
ans|=query(R(id),l,r);
return ans;
}
void cdq(int l,int r)
{
if(l==r)
return ;
int m=(l+r)>>;
cdq(l,m);
cdq(m+,r);
int i=l,j=m+,k=l;
while(i<=m&&j<=r)
{
if(P[i]<P[j])
{
if(P[i].op==)
updata(,P[i].y,P[i].val);
temp[k++]=P[i++];
}
else
{
if(P[j].op==)
ans[P[j].val]|=query(,P[j].y,P[j].y1);
temp[k++]=P[j++];
}
}
while(i<=m)
temp[k++]=P[i++];
while(j<=r)
{
if(P[j].op==)
ans[P[j].val]|=query(,P[j].y,P[j].y1);
temp[k++]=P[j++];
}
for(i=l;i<=r;i++)
{
if(P[i].op==)
updata(,P[i].y,);
P[i]=temp[i];
}
}
void solve()
{
if(pn)
{
//离散化部分
sort(vy.begin(),vy.end());
for(int i=;i<vy.size();i++)
{
newy[vy[i]]=i+;
num[vy[i]]=;
}
for(int i=;i<pn;i++)
{
if(P[i].op==)
P[i].y=newy[P[i].y];
else
P[i].y=newy[P[i].y],P[i].y1=newy[P[i].y1];
}
//进行分治
cdq(,pn-);
}
for(int i=;i<qn;i++)
{
int sum=;
//判断2^0+2^1+2^2+...+2^50含有哪些
for(int j=;j<=;j++)
if(ans[i]&cf2[j])
sum++;
printf("%d\n",sum);
ans[i]=;
}
pn=qn=;
vy.clear();
}
int main()
{
int op,x,y,c,y1;
built(,,N);
for(int i=;i<=;i++)
cf2[i]=cf2[i-]<<;
while(~scanf("%d",&op)&&op!=)
{
if(op==)
solve();
else if(op==)
{
scanf("%d%d%d",&x,&y,&c);
addp(,x,y,,cf2[c]);
addy(y);
}
else
{
scanf("%d%d%d",&x,&y,&y1);
addp(,x,y,y1,qn++);
addy(y);
addy(y1);
}
}
solve();
return ;
}
一分二二分四
但实际上,3个实现方法中,暴力最快。。。数据太坑了
HDU - 6183 暴力,线段树动态开点,cdq分治的更多相关文章
- HDU - 6183:Color it (线段树&动态开点||CDQ分治)
Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B ...
- BZOJ_4636_蒟蒻的数列_线段树+动态开点
BZOJ_4636_蒟蒻的数列_线段树+动态开点 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将 ...
- hdu6183 Color it 线段树动态开点+查询减枝
题目传送门 题目大意: 有多次操作.操作0是清空二维平面的点,操作1是往二维平面(x,y)上放一个颜色为c的点,操作2是查询一个贴着y轴的矩形内有几种颜色的点,操作3退出程序. 思路: 由于查询的矩形 ...
- P3939 数颜色 线段树动态开点
P3939 数颜色 线段树动态开点 luogu P3939 水.直接对每种颜色开个权值线段树即可,注意动态开点. #include <cstdio> #include <algori ...
- 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点
题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...
- codedecision P1113 同颜色询问 题解 线段树动态开点
题目描述:https://www.cnblogs.com/problems/p/11789930.html 题目链接:http://codedecision.com/problem/1113 这道题目 ...
- hdu 6183 Color it (线段树 动态开点)
Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B ...
- BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...
- 2019.03.09 bzoj4999: This Problem Is Too Simple!(树链剖分+线段树动态开点)
传送门 题意:给一颗树,每个节点有个初始值,要求支持将i节点的值改为x或询问i节点到j节点的路径上有多少个值为x的节点. 思路: 考虑对每种颜色动态开点,然后用树剖+线段树维护就完了. 代码: #in ...
随机推荐
- Linux(CentOS)下安装NVIDIA GPU驱动
GCC 官网:http://gcc.gnu.org 1)检查 NVIDIA驱动需要GCC等C/C++开发环境,首先检测GCC是否已经安装 gcc –v# 如果系统显示没有找到GCC指令,或没有显示GC ...
- python---博客分类目录
python基础 python函数 python模块 python面向对象 网络编程 并发编程 数据库 前端学习 HTML基础 CSS基础 JavaScript基础 js操作BOM和DOM jQuer ...
- Wannafly挑战赛24
A. 石子游戏 Alice和Bob在玩游戏,他们面前有n堆石子,对于这些石子他们可以轮流进行一些操作,不能进行下去的人则输掉这局游戏.可以进行两种操作:1. 把石子数为奇数的一堆石子分为两堆正整数个石 ...
- 3-Perl 基础语法
Perl 基础语法Perl借用了C.sed.awk.shell脚本以及很多其他编程语言的特性,语法与这些语言有些类似,也有自己的特点.Perl 程序有声明与语句组成,程序自上而下执行,包含了循环,条件 ...
- c#中异常捕获,回滚
语法: try { 有可能出现错误的代码写在这里 } catch { 出错后的处理 } 如果try中的代码没有出错,则程序正常运行try中的内容后,不会执行catch中的内容, 如果try中的代码一但 ...
- vue transtion 实现分析
这是我用js和css3,实现的vue transition组件相同的效果核心js var btn = document.getElementById('btn'); var box = null bt ...
- vue axios异步请求django
1,配置请求路径 (1),vue中的请求路径要与django视图路径相同. (2),vue中的路由路径也要和django视图路径相同,比如视图路径为127.0.0.1:8000:home/index, ...
- Linux--环境变量配置文件
Linux系统中环境变量配置文件分为两类: 全局环境变量配置文件 /etc/profile 用户环境变量配置文件 ~/.bash_profile . ~/.bash_login ~/.profile ...
- vue-element-admin 多层路由问题
在二级页面上添加<router-view> 关于页面打包后三级路由无法访问问题 需要将 存放router-view 的页面单独存放一个文件夹 router.js 写法
- ffmpeg处理视频命令
一:视频添加图片水印 ffmpeg -i a.mp4 -vf "movie=a.jpg[watermark];[in][watermark] overlay=main_w-overlay_w ...