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 ...
随机推荐
- Sentinal LDK 加密狗的使用
公司的软件用了第三方的加密key,在代码里只是用了其中的一个功能:GetKeyInfo()判断电脑是否有插入u盾.现做简单的说明如下: 第一步.插入master key 到电脑,下载正式的hvc 授权 ...
- python函数篇0-2
函数的有三中不同的参数: 普通参数 默认参数 动态参数# ######### 定义函数 ######### # name 叫做函数func的形式参数,简称:形参def func(name): p ...
- python安装OpenCV后import cv2报错解决办法
现在python安装完成后,运行pip install opencv-python安装成功后,import cv2时会失败 看到有人给出下载https://www.lfd.uci.edu/~gohlk ...
- 树莓派和STM32通过USB和串口通信记录
不管怎样,为了简便开发,通信选择串口通信. 推荐文章:https://blog.csdn.net/magnetoooo/article/details/53564797 推荐测试工具:https:// ...
- Centos7.3安装Oracle11.2.0.3
1.创建用户用户组 [root@smallcloud ~]# groupadd oinstall [root@smallcloud ~]# groupadd dba [root@smallcloud ...
- mysql+canal+kafka+elasticsearch构建数据查询平台
1. 实验环境 CPU:4 内存:8G ip:192.168.0.187 开启iptables防火墙 关闭selinux java >=1.5 使用yum方式安装的java,提前配置好JAVA_ ...
- lesson12Homework
package StringPractice; public class arrayTest { //1. 把A数组的前5个元素复制到B数组中. public static void main(Str ...
- [转载]Flex的文件规则
原文在:https://blog.csdn.net/hczhiyue/article/details/20483209 文章中给的一个定义很明白,对于初学者来说很有帮助: 什么是 FLEX?它是一个自 ...
- 小白进阶之Scrapy第六篇Scrapy-Redis详解(转)
Scrapy-Redis 详解 通常我们在一个站站点进行采集的时候,如果是小站的话 我们使用scrapy本身就可以满足. 但是如果在面对一些比较大型的站点的时候,单个scrapy就显得力不从心了. 要 ...
- odoo 常用模型的简写
<act_window>是窗口操作模型ir.actions.act_window <menuitem>是菜单项模型ir.ui.menu <report>是报表操作模 ...