cdq分治入门--BZOJ1176: [Balkan2007]Mokia

对w*w,w<=2000000的矩形,一开始全是0(或一开始全是s),n<=170000个操作,每次操作:矩阵内某点加上一个数,查某一个子矩阵的和,保证修改数<=160000,询问数<=10000。

这还是一个比较明显的三维偏序:时间维,以及x和y。由于现在时间维是一个Ti<Tj,而x和y是要查x1<=x<=x2,y1<=y<=y2,查一个范围答案在归并排序直接查不方便,所以一个询问拆4个,就变成普通的三维偏序了。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 //#include<iostream>
 6 using namespace std;
 7
 8 int n,m,s;
 9 #define maxn 300011
10 #define maxm 2000011
11 struct Point
12 {
13     int x,y,v;bool type;
14     //type=1:Q type=0:A
15 }a[maxn];
16 int ans[maxn];
17
18 struct BIT
19 {
20     int a[maxm],n;
21     void clear(int m) {n=m;memset(a,0,sizeof(a));}
22     void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;}
23     int query(int x) {int ans=0;for (;x;x-=x&-x) ans+=a[x];return ans;}
24 }t;
25
26 int ord[maxn],tmpord[maxn];
27 void solve(int L,int R)
28 {
29     if (L==R) {ord[L]=L;return;}
30     const int mid=(L+R)>>1;
31     solve(L,mid);
32     solve(mid+1,R);
33     int i=L,j=mid+1,k=L;
34     while (i<=mid && j<=R)
35     {
36         if (a[ord[i]].x<=a[ord[j]].x)
37         {
38             if (a[ord[i]].type==0)
39                 t.add(a[ord[i]].y,a[ord[i]].v);
40             tmpord[k++]=ord[i++];
41         }
42         else
43         {
44             if (a[ord[j]].type)
45                 ans[ord[j]]+=t.query(a[ord[j]].y);
46             tmpord[k++]=ord[j++];
47         }
48     }
49     for (;j<=R;j++)
50     {
51         if (a[ord[j]].type) ans[ord[j]]+=t.query(a[ord[j]].y);
52         tmpord[k++]=ord[j];
53     }
54     for (int ii=L;ii<i;ii++) if (!a[ord[ii]].type) t.add(a[ord[ii]].y,-a[ord[ii]].v);
55     for (;i<=mid;i++) tmpord[k++]=ord[i];
56     for (int x=L;x<=R;x++) ord[x]=tmpord[x];
57 }
58
59 int main()
60 {
61     scanf("%d%d",&s,&m);
62     t.clear(m);
63     n=0;
64     int op,x,y,z,w;
65     while (scanf("%d",&op) && op!=3)
66     {
67         if (op-1)
68         {
69             scanf("%d%d%d%d",&x,&y,&z,&w);
70             a[++n]=(Point){x-1,y-1,1,1};
71             a[++n]=(Point){x-1,w,-1,1};
72             a[++n]=(Point){z,y-1,-1,1};
73             a[++n]=(Point){z,w,1,1};
74         }
75         else
76         {
77             scanf("%d%d%d",&x,&y,&z);
78             a[++n]=(Point){x,y,z,0};
79         }
80     }
81     solve(1,n);
82
83     for (int i=1;i<=n;i++) if (a[i].type)
84     {
85         int Ans=0;
86         for (int to=i+4;i<to;i++) Ans+=ans[i]*a[i].v;
87         i--;
88         printf("%d\n",Ans);
89     }
90     return 0;
91 }

这题面的s没有用,怎么题面也不改。。

时间: 2024-10-10 19:46:58

cdq分治入门--BZOJ1176: [Balkan2007]Mokia的相关文章

[BZOJ1176][Balkan2007]Mokia cdq+树状数组

1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 3134  Solved: 1395[Submit][Status][Discuss] Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

COGS 577 蝗灾 [CDQ分治入门题]

题目链接 昨天mhr神犇,讲分治时的CDQ分治的入门题. 题意: 你又一个w*w正方形的田地. 初始时没有蝗虫. 给你两个操作: 1. 1 x y z: (x,y)这个位置多了z只蝗虫. 2. 2 x1 y1 x2 y2: 询问(x1,y1)到(x2,y2)这个矩形内的蝗虫数量. 其中 W<=500000,操作数<=200000 . 题解: w范围太大,无法使用二维数据结构. 于是我们可以分治操作. CDQ分治:定义 solve(l,r) 设m=(l+r)/2; 先计算 l-m 修改操作对 m

bzoj千题计划144:bzoj1176: [Balkan2007]Mokia

http://www.lydsy.com/JudgeOnline/problem.php?id=1176 CDQ分治 #include<cstdio> #include<iostream> #include<algorithm> #define lowbit(x) x&-x using namespace std; #define N 160001 #define M 10001 typedef long long LL; int w; LL c[2000001

BZOJ1176: [Balkan2007]Mokia CDQ分治

最近很不对啊=w= 写程序全是bug啊 ans数组开小了竟然一直不知道,小数据没问题大数据拍不过,交上去RE 蛋疼半天 这个主要把每次询问拆成3个询问. #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<iostream> #define dout printf using namespace std; const int Maxw=

cdq分治入门--BZOJ1492: [NOI2007]货币兑换Cash

n<=100000天,一开始有s块钱,每天股票A价格ai,B价格bi,每天可以做的事情:卖出股票:按A:B=RTi的比例买入股票.问最后的最大收益.股票可以为浮点数,答案保留三位. 用脚指头想想就知道是:某一天全部买进来,某一天全部卖出去,没有说买一半卖一半的. 那就可以dp了,f(i)表示前i天最大收益,,其中Xi表示用f(i)块钱在第i天能买多少A券,Yi表示f(i)块前第i天买多少B券,可以自己算,n方过不了. 现要找max(Ai*Xj+Bi*Yj),考虑两个状态j,k,j比k优时 整理得

cdq分治入门--BZOJ3262: 陌上花开

n<=100000个人,每个人三个属性Ai,Bi,Ci,一个人i的等级为Ai>=Aj,Bi>=Bj,Ci>=Cj的人数,求每个等级有多少人. 裸的三维偏序.按照常规思路,一维排序,一维归并,一维利用单调性或用树状数组维护,这里选择后者. 先按Ai排序,然后在分治过程中,solve(l,mid),solve(mid+1,r),然后考虑(l,mid)对(mid+1,r)答案的贡献,先把这两部分分别按B排序,然后两个指针一起扫,扫的过程中,把C的值作下标丢进树状数组,查询时相当于树状数组

BZOJ1176 [Balkan2007]Mokia

就是整体二分啦... 然后我们把一个矩形的询问拆成四个,按x排序按y加入bit中就可以O(n * logn^2)做出来啦~ 1 /************************************************************** 2 Problem: 1176 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:4620 ms 7 Memory:25808 kb 8 *********************

【kd-tree】bzoj1176 [Balkan2007]Mokia

裸题不多说,注意在sqrt(n*log(n))次插入后重构树以保持深度. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 170011 #define KD 2//ά¶ÈÊý int qp[2][2]; int n,root=1,m; int Begin; bool dn; struct Node { int minn[KD],maxx[KD],p[

cdq分治浅谈

$cdq$分治浅谈 1.分治思想 分治实际上是一种思想,这种思想就是将一个大问题划分成为一些小问题,并且这些小问题与这个大问题在某中意义上是等价的. 2.普通分治与$cdq$分治的区别 普通分治与$cdq$分治都是基于分治思想之上的算法,但是他们是有区别的.普通分治的适用条件是,产生的小问题之间互不影响,然而$cdq$分治就相对比较宽泛,小问题之间可以有影响,但是$cdq$分治不支持强制在线. 3.$cdq$分治浅谈 分治一共分为四步: 1) 将当前处理区间分为左右两个等大的子区间: 2) 递归