cogs 1752 [BOI2007]摩基亚Mokia(cdq分治+树状数组)
来源:互联网 发布:积分统计软件 编辑:程序博客网 时间:2024/05/21 19:25
数据范围过大,所以没有办法二维树状数组和二维线段树什么的。
听说kdtree可做?然而还不会。
这时候cdq分治就派上用场了,首先它不需要二维的空间,所有空间上是没问题的,然后时间复杂度也可以,具体时间复杂度分析下面再说。
这个问题其实可以看成一个三维偏序问题,(时间,横坐标,纵坐标)。
三维貌似看起来有些头疼,假如是二维呢,比如 问题是动态加点,询问一条线段里包含的权值和,
那样就是(时间,坐标)的一个二维偏序,对于我一个查询可以看成(a,b),(a,c)的两个偏序,a代表查询的时间,b,c代表线段的两个端点,那么我们如果找到时间小于a,坐标小于c的的权值和,再减去同样的比较方法小于(a,b)的权值和,不就求出了这一时刻这条线段里包含的权值和了嘛。
那么三维不就是把坐标扩大,按照求二维前缀和的方式去求容斥一下就好了?
我们需要先将一次询问转换为四次不同的二维前缀和查询操作,然后对于每一个询问,我们需要求出左区间(时间小于自己)里,横坐标小于自己纵坐标也小于自己的权值和,
时间已经满足,横坐标的话可以通过cdq分治时顺带的归并排序确定出横坐标小于自己的连续操作区间,但是纵坐标就需要用树状数组统计一下相应的权值了,在查询的时候再求出纵坐标小于自己的点的权值,每次分治的结束的时候都清空下树状数组,就做完了。
cdq分治递归logn层,每层o(n)的操作,然后加上一个树状数组的logn,时间复杂度就是nlog^nlog^2了。
cogs oj给出数据什么的真的好评,但是我数组开小了,应该re竟然返回wa了。
代码:
#include <stdio.h>//using namespace std;const int maxn=2e6+5;int ans[10005];struct node{ int t; int x; int y; int qid; int val; int type; bool operator <(const node & a)const { return a.x==x?type<a.type:x<a.x; }}que[maxn], tmp[maxn];int n;int val[maxn];int lowbit(int x){ return x&-x;}void add(int x, int y){ while(x<maxn) { val[x]+=y; x+=lowbit(x); } return; }int sum(int x){ int res=0; while(x>0) { res+=val[x]; x-=lowbit(x); } return res;}void cdq(int l, int r){ if(r-l<=1)return; int mid=(l+r)>>1; cdq(l, mid); cdq(mid, r); int p=l, q=mid, o=0;// printf("%d %d\n", l, r); while(p<mid && q<r) { if(que[p]<que[q]) { if(que[p].type==1) { add(que[p].y, que[p].val); } tmp[o++]=que[p++]; } else { if(que[q].type==2) { ans[que[q].qid]+=que[q].val*sum(que[q].y); // printf("%d %d %d %d %d\n", que[q].x, que[q].y, que[q].val, que[q].qid, ans[que[q].qid]); } tmp[o++]=que[q++]; } } while(q<r) { if(que[q].type==2) { ans[que[q].qid]+=que[q].val*sum(que[q].y); // printf("%d %d %d %d %d\n", que[q].x, que[q].y, que[q].val, que[q].qid, ans[que[q].qid]); } tmp[o++]=que[q++]; } /* memset(val, 0, sizeof val); */ for(int i=l; i<p; i++)if(que[i].type==1)add(que[i].y, que[i].val*-1); while(p<mid) { tmp[o++]=que[p++]; } for(int i=0; i<o; i++)que[i+l]=tmp[i]; return;}int main(){ /* freopen("mokia.in", "r", stdin); freopen("mokia.out", "w", stdout); */ scanf("%*d%d", &n); int x, y, x1, y1, e, id=1, qid=1; while(~scanf("%d", &e)) { if(e==3)break; if(e==1) { scanf("%d%d%d", &que[id].x, &que[id].y, &que[id].val); que[id].t=id; que[id].type=1; } else { scanf("%d%d%d%d", &x, &y, &x1, &y1); que[id].t=id, que[id].x=x-1, que[id].y=y-1, que[id].val=1, que[id].qid=qid, que[id].type=2; id++; que[id].t=id, que[id].x=x-1, que[id].y=y1, que[id].val=-1, que[id].qid=qid, que[id].type=2; id++; que[id].t=id, que[id].x=x1, que[id].y=y-1, que[id].val=-1, que[id].qid=qid, que[id].type=2; id++; que[id].t=id, que[id].x=x1, que[id].y=y1, que[id].val=1, que[id].qid=qid, que[id].type=2; qid++; } id++; } cdq(1, id); for(int i=1; i<qid; i++) { printf("%d\n", ans[i]); }}
阅读全文
0 0
- cogs 1752 [BOI2007]摩基亚Mokia(cdq分治+树状数组)
- cogs [BOI2007]摩基亚Mokia CDQ 分治
- 【COGS】1752. [BOI2007]摩基亚Mokia cdq分治模板题
- [BOI2007]摩基亚Mokia (cdq分治)
- 【BZOJ1176】【BOI2007】Mokia & 【BZOJ2683】简单题(CDQ分治+树状数组)
- 1752. [BOI2007]摩基亚Mokia (cdq分治模板题)
- cogs 1752. [BOI2007]摩基亚Mokia
- [BZOJ1176][Balkan2007]Mokia && CDQ分治+树状数组
- BZOJ_P1176 [Balkan2007]Mokia(CDQ分治+树状数组)
- [bzoj1176][Balkan2007]Mokia cdq分治+树状数组
- [BZOJ1176][Balkan2007]Mokia-CDQ分治+树状数组
- COGS 577 蝗灾 cdq分治+树状数组
- 1176: [Balkan2007]Mokia/2683: 简单题 CDQ分治+树状数组
- 【bzoj 1176】[Balkan2007] Mokia(cdq分治+树状数组)
- BZOJ 1176: [Balkan2007]Mokia【CDQ分治+树状数组
- BZOJ 1176 [Balkan2007]Mokia [CDQ分治+树状数组]
- COGS 2479. [HZOI 2016]偏序 双重CDQ分治+树状数组
- 【BOI2007】BZOJ1176 CDQ分治
- 队列的存储结构,判空、插入、删除操作
- applicationContext.xml的基本配置文件
- 通过服务器日志溯源web应用攻击路径
- iOS开发-- 字符串分割(多个字符分割一个字符串)、拼接
- error LNK2026: 模块对于 SAFESEH 映像是不安全的-VS2013
- cogs 1752 [BOI2007]摩基亚Mokia(cdq分治+树状数组)
- c++中函数重在的实现原理
- CCF 1153素数环
- Layered Window 透明窗体的实现总结
- Linux 内存管理浅析
- elasticsearch-翻译完结篇
- [kuangbin带你飞]专题九 连通图 A
- 汉诺塔相关问题及例题
- 查看MySQL数据库版本号的方法