B - Color itHDU - 6183

  题目大意:有三种操作,0是清空所有点,1是给点(x,y)涂上颜色c,2是查询满足1<=a<=x,y1<=b<=y2的(a,b)点一共有几种不同的颜色

  一开始做的时候直接就是开51个vector保存每个颜色相应的点,然后就是询问就是,暴力循环判断这个颜色存不存在一个满足条件的点,感觉最差情况下应该会超时,不过却过了

 1 #include<cstdio>
 2 #include<vector>
 3 using namespace std;
 4 struct Node{
 5     int x,y;
 6     Node(){}
 7     Node(int x,int y):x(x),y(y){}
 8 };
 9 vector<Node> c[58];
10 int main()
11 {
12     int op,x,y,y1,cc;
13     while(scanf("%d",&op)&&op!=3)
14     {
15         if(op==0)
16         {
17             for(int i=0;i<=50;i++)
18                 c[i].clear();
19         }
20         else if(op==1)
21         {
22             scanf("%d%d%d",&x,&y,&cc);
23             c[cc].push_back(Node(x,y));
24         }
25         else
26         {
27             scanf("%d%d%d",&x,&y,&y1);
28             int ans=0;
29             for(int i=0;i<=50;i++)
30             {
31                 for(int j=0;j<c[i].size();j++)
32                     if(c[i][j].x<=x&&c[i][j].y>=y&&c[i][j].y<=y1)
33                     {
34                         ans++;
35                         break;
36                     }
37             }
38             printf("%d\n",ans);
39         }
40     }
41     return 0;
42 }

暴力过一切

  然后看网上有是线段树动态开点的做法,但实际上并不比上面暴力的写法快,反而慢上几十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的关系了,所以我们要保存下的是它的左右孩子的编号已经一系列相关的信息,然后对于每个节点就是当需要到它时再开辟它。其他操作就和静态的线段树差不多。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=1001108;
 5 struct Tree{
 6     int lson,rson,minx;
 7 }T[N];
 8 int tn,flag,root[52];
 9 //root就保存这个颜色对于的那棵线段树的根节点编号
10 void init()
11 {
12     tn=1;
13     for(int i=0;i<=50;i++)
14         root[i]=0;
15 }
16 void updata(int &id,int L,int R,int y,int x)//在这里用L,R来表示节点id的区间
17 {
18     if(!id)
19     {//需要到这个节点了,开辟这个节点
20         id=tn++;
21         T[id].minx=N;
22         T[id].lson=T[id].rson=0;//它的子节点还未用得上
23     }
24     T[id].minx=min(T[id].minx,x);//更新最小的x值
25     //下面就是线段树的单点修改
26     if(L==R)
27         return ;
28     int mid=(L+R)>>1;
29     if(y<=mid)
30         updata(T[id].lson,L,mid,y,x);
31     else
32         updata(T[id].rson,mid+1,R,y,x);
33 }
34 void query(int id,int L,int R,int l,int r,int x)
35 {
36     if(flag||!id)//如果已经有点满足条件,或者这个节点没开辟就返回
37         return ;
38     if(l<=L&&r>=R)
39     {
40         if(T[id].minx<=x)
41             flag=1;//在y1和y2范围内有个x满足条件
42         return ;
43     }
44     int mid=(L+R)>>1;
45     if(l<=mid)
46         query(T[id].lson,L,mid,l,r,x);
47     if(r>mid)
48         query(T[id].rson,mid+1,R,l,r,x);
49 }
50 int main()
51 {
52     int op,x,y,y2,c;
53     init();
54     while(~scanf("%d",&op)&&op!=3)
55     {
56         if(op==0)
57             init();
58         else if(op==1)
59         {
60             scanf("%d%d%d",&x,&y,&c);
61             updata(root[c],1,1000000,y,x);
62         }
63         else
64         {
65             scanf("%d%d%d",&x,&y,&y2);
66             int ans=0;
67             for(int i=0;i<=50;i++)
68             {
69                 flag=0;
70                 query(root[i],1,1000000,y,y2,x);
71                 ans+=flag;
72             }
73             printf("%d\n",ans);
74         }
75     }
76     return 0;
77 }

线段树下线段果

  正解是cdq分治,待我学成归来,再更新。。。我回来了

  cdq分治处理的话,就是三维偏序的一个处理,(操作时间,x轴,y轴),然后第一维已经有序,那么我们cdq分治处理第二维,然后线段树处理第三维。因为最多是50种颜色,那么我们采用状压的策略,把每个颜色C用2C来表示,然后线段树维护个区间或和。需要注意的就是y轴离散化下,不然容易超时。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<vector>
  4 #define L(x) (x<<1)
  5 #define R(x) (x<<1|1)
  6 #define M(x) ((T[x].l+T[x].r)>>1)
  7 using namespace std;
  8 typedef long long ll;
  9 const int N=150118,Y=1000118;
 10 struct Tree{
 11     int l,r;
 12     ll val;
 13 }T[Y];
 14 struct Nop{
 15     int op,x,y,y1;
 16     ll val;//op1更新操作的val记录2^C,op2查询操作记录答案编号
 17     friend bool operator <(const Nop &n1,const Nop &n2){
 18         return n1.x==n2.x ? n1.op<n2.op : n1.x<n2.x;
 19     }
 20 }P[N<<1],temp[N<<1];
 21 int pn=0,qn=0,newy[Y];
 22 bool num[Y]={0};
 23 vector<int> vy;
 24 ll ans[N]={0},cf2[52]={1};
 25 inline void addp(int op,int x,int y,int y1,ll val){
 26     P[pn++]=(Nop){op,x,y,y1,val};
 27 }
 28 inline void addy(int y)
 29 {
 30     if(!num[y])
 31     {
 32         num[y]=1;
 33         vy.push_back(y);
 34     }
 35 }
 36 void built(int id,int l,int r)
 37 {
 38     T[id].val=0;
 39     T[id].l=l,T[id].r=r;
 40     if(l==r)
 41         return ;
 42     built(L(id),l,M(id));
 43     built(R(id),M(id)+1,r);
 44 }
 45 //线段树单点修改
 46 void updata(int id,int pos,ll val)
 47 {
 48     if(T[id].l==T[id].r&&T[id].l==pos)
 49     {
 50         if(val)
 51             T[id].val|=val;
 52         else
 53             T[id].val=0;
 54         return ;
 55     }
 56     if(pos<=M(id))
 57         updata(L(id),pos,val);
 58     else
 59         updata(R(id),pos,val);
 60     T[id].val=T[L(id)].val|T[R(id)].val;
 61 }
 62 //区间或和查询
 63 ll query(int id,int l,int r)
 64 {
 65     ll ans=0;
 66     if(l<=T[id].l&&T[id].r<=r)
 67         return T[id].val;
 68     if(l<=M(id))
 69         ans|=query(L(id),l,r);
 70     if(r>M(id))
 71         ans|=query(R(id),l,r);
 72     return ans;
 73 }
 74 void cdq(int l,int r)
 75 {
 76     if(l==r)
 77         return ;
 78     int m=(l+r)>>1;
 79     cdq(l,m);
 80     cdq(m+1,r);
 81     int i=l,j=m+1,k=l;
 82     while(i<=m&&j<=r)
 83     {
 84         if(P[i]<P[j])
 85         {
 86             if(P[i].op==1)
 87                 updata(1,P[i].y,P[i].val);
 88             temp[k++]=P[i++];
 89         }
 90         else
 91         {
 92             if(P[j].op==2)
 93                 ans[P[j].val]|=query(1,P[j].y,P[j].y1);
 94             temp[k++]=P[j++];
 95         }
 96     }
 97     while(i<=m)
 98         temp[k++]=P[i++];
 99     while(j<=r)
100     {
101         if(P[j].op==2)
102             ans[P[j].val]|=query(1,P[j].y,P[j].y1);
103         temp[k++]=P[j++];
104     }
105     for(i=l;i<=r;i++)
106     {
107         if(P[i].op==1)
108             updata(1,P[i].y,0);
109         P[i]=temp[i];
110     }
111 }
112 void solve()
113 {
114     if(pn)
115     {
116         //离散化部分
117         sort(vy.begin(),vy.end());
118         for(int i=0;i<vy.size();i++)
119         {
120             newy[vy[i]]=i+1;
121             num[vy[i]]=0;
122         }
123         for(int i=0;i<pn;i++)
124         {
125             if(P[i].op==1)
126                 P[i].y=newy[P[i].y];
127             else
128                 P[i].y=newy[P[i].y],P[i].y1=newy[P[i].y1];
129         }
130         //进行分治
131         cdq(0,pn-1);
132     }
133     for(int i=0;i<qn;i++)
134     {
135         int sum=0;
136         //判断2^0+2^1+2^2+...+2^50含有哪些
137         for(int j=0;j<=50;j++)
138             if(ans[i]&cf2[j])
139                 sum++;
140         printf("%d\n",sum);
141         ans[i]=0;
142     }
143     pn=qn=0;
144     vy.clear();
145 }
146 int main()
147 {
148     int op,x,y,c,y1;
149     built(1,1,N);
150     for(int i=1;i<=50;i++)
151         cf2[i]=cf2[i-1]<<1;
152     while(~scanf("%d",&op)&&op!=3)
153     {
154         if(op==0)
155             solve();
156         else if(op==1)
157         {
158             scanf("%d%d%d",&x,&y,&c);
159             addp(1,x,y,0,cf2[c]);
160             addy(y);
161         }
162         else
163         {
164             scanf("%d%d%d",&x,&y,&y1);
165             addp(2,x,y,y1,qn++);
166             addy(y);
167             addy(y1);
168         }
169     }
170     solve();
171     return 0;
172 }

一分二二分四

  但实际上,3个实现方法中,暴力最快。。。数据太坑了

转载于:https://www.cnblogs.com/LMCC1108/p/10699522.html

HDU - 6183 暴力,线段树动态开点,cdq分治相关推荐

  1. 线段树动态开点区间加区间求和

    线段树动态开点区间加区间求和 题目来源: 陕西师范大学第七届程序设计竞赛网络同步赛 H. 万恶的柯怡 思想: 保证叶子节点被完整的覆盖,需要开节点,就把左右儿子都开出来,其余和普通线段树一样. tip ...

  2. ZYH的斐波那契数列【线段树动态开点+矩阵快速幂求斐波那契】

    描述 ZYH最近研究数列研究得入迷啦! 现在有一个斐波拉契数列(f[1]=f[2]=1,对于n>2有f[n]=f[n-1]+f[n-2]), 但是斐波拉契数列太简单啦,于是ZYH把它改成了斐波拉 ...

  3. 【题解】有便便的厕所(权值线段树动态开点模板题)

    我只是来填坑的. 关于权值线段树的更多有关内容见此. 题面 题目描述 众所周知, GM \texttt{GM} GM 家的狗特别喜欢拉便便. GM \texttt{GM} GM 为了方便它方便,在家里 ...

  4. HDU - 5709 Claris Loves Painting 线段树动态开点+合并

    题目链接:https://cn.vjudge.net/problem/HDU-5709 题意:给定一棵n点的树,每个节点上有一个颜色,每次询问一个点的子树中与这个点距离不超过d的点的颜色有多少种 题解 ...

  5. BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)

    传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...

  6. Codeforces Round #737 (Div. 2) D. Ezzat and Grid 线段树动态开点

    传送门 文章目录 题意: 思路: 题意: 思路: 比较套路的一个题,我们维护一个dp[i]dp[i]dp[i]表示到了第iii行能保留的区间最多是多少. 转移比较明显:dp[i]=max(dp[j]) ...

  7. 线段树动态开点 - - - > 线段树合并

    逆序对 代码 P3224 [HNOI2012]永无乡 并查集+线段树合并       ​​​​ 代码 P5494 [模板]线段树分裂 #include<iostream> #include ...

  8. 权值线段树+动态开点(学习小结)

    首先先上一道板题:把它看懂就OK了,其实这个跟普通的线段树也没太大区别,就是存的是出现的次数. CODE #include<algorithm> #include<cstdio> ...

  9. HDU 2795 Billboard (线段树+贪心)

    HDU 2795 Billboard (线段树+贪心) 手动博客搬家:本文发表于20170822 21:30:17, 原地址https://blog.csdn.net/suncongbo/articl ...

最新文章

  1. P1119 灾后重建(经典floyd)
  2. Apache Ivy
  3. 面对万物互联的智能世界,你是否也想分一杯羹
  4. 键盘出现与消失的监听方法
  5. 06-02 Jenkins job 机制
  6. webpack文件系统缓存
  7. 实验4-1-2 求奇数和 (15 分)
  8. 拓端tecdat|R语言文本挖掘使用tf-idf分析NASA元数据的关键字
  9. 6 使用soap客户端_SOAP技术应用总结
  10. Python100道经典练习题(附PDF)
  11. 线性代数 --- 线性代数中的一些特殊矩阵(被广泛用于高斯消元法的消元矩阵E)(个人笔记扫描版)
  12. PV-RCNN: Point-Voxel Feature Set Abstraction for 3D Object Detection阅读
  13. keepalived配置文件相关简单解释
  14. 程序员必读: 摸清Hash表的脾性
  15. linux 卸载windows系统服务,如何卸载windows系统
  16. Scrapy 第一次爬虫
  17. 数据恢复原理与数据清除原理
  18. 坚持#第369天~知道了惠普打印机和佳能打印机打印不清晰了怎么解决
  19. 网络能力认证CCSC-管理1级 技术1级别
  20. python安装lap_AP 升级到 LAP,或 LAP 降到 AP 的方法

热门文章

  1. SpringMVC,SpringBoot文件下载
  2. Spring/Spring Boot微服务项目 集成Druid 实现监控功能
  3. 【python】Python中给List添加元素的4种方法分享
  4. visual studio 2015开发nodejs教程1搭建环境
  5. linux的mysql修改用户密码与忘记密码的方法
  6. linux中locate find 与 grep
  7. 定位服务器数据丢弃包问题
  8. Git : 将本地git仓库同步到远端github上
  9. Mysql实战:主从同步
  10. 多线程:并发实现方法之J.U.C