【BZOJ 4170】 4170: 极光 (CDQ分治)

4170: 极光

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 121  Solved: 64

Description

"若是万一琪露诺(俗称rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她。对方表现出兴趣的话,那就慢

慢地反问。在她考虑答案的时候,趁机逃吧。就算是很简单的问题,她一定也答不上来。"

--《上古之魔书》

天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:2个位置的g

raze值为两者位置差与数值差的和:

graze(x,y)=|x-y|+|a[x]-a[y]|。

要想破解天罚,就必须支持2种操作(k都是正整数):

Modify x k:将第x个数的值修改为k。

Query x k:询问有几个i满足graze(x,i)<=k。

由于从前的天罚被圣王lmc破解了,所以rhl改进了她的法术,询问不仅要考虑当前数列,还要考虑任意历史版本,

即统计任意位置上出现过的任意数值与当前的a[x]的graze值<=k的对数。(某位置多次修改为同样的数值,按多次

统计)

Input

第1行两个整数n,q。分别表示数列长度和操作数。

第2行n个正整数,代表初始数列。

第3~q+2行每行一个操作。

N<=40000, 修改操作数<=40000, 询问操作数<=10000, Max{a[i]}(含修改)<=80000

Output

对于每次询问操作,输出一个非负整数表示答案

Sample Input

3 5

2 4 3

Query 2 2

Modify 1 3

Query 2 2

Modify 1 2

Query 1 1

Sample Output

2

3

3

HINT

Source

【分析】

  那个公式是曼哈顿距离的形式,把编号看成x,数值看成y,那就是在二维平面上不断给你一些点,然后问你距离某个点曼哈顿距离小于等于k的有多少个。

  曼哈顿距离画出来是一个菱形区域,把它旋转,即(x,y)->(x-y,x+y),就是一个矩形区域,根据容斥分成4段求前缀。

  那么加一个时间维就是一个经典的CDQ模型啦,三维偏序嘛~

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 40010
 8 #define Maxm 50010
 9
10 struct node {int a,b,c,id,f,ans;}t[Maxn*10];
11 int len=0;
12 int ans[Maxm*10],w[Maxn*10];
13 char s[10];
14 int n,q;
15
16 void add(int a,int b,int c,int id,int f)
17 {
18     // printf("%d %d %d %d %d\n",a,b,c,id,f);
19     t[++len].a=a;t[len].b=b;t[len].c=c;t[len].id=id;t[len].f=f;
20     t[len].ans=0;
21 }
22
23 bool cmp(node x,node y)
24 {
25     if(x.a!=y.a) return x.a<y.a;
26     return (x.b==y.b)?(x.c<y.c):(x.b<y.b);
27 }
28 bool cmp2(int x,int y) {return (t[x].b==t[y].b)?(t[x].c<t[y].c):(t[x].b<t[y].b);}
29
30 int cc[Maxm*10],nw[Maxm*10];
31 void ad(int x,int y) {for(int i=x;i<=q+1;i+=i&(-i)) cc[i]+=y;}
32 int query(int x) {int as=0;for(int i=x;i>=1;i-=i&(-i)) as+=cc[i];return as;}
33
34 void ffind(int l,int r)
35 {
36     if(l==r) return;
37     int mid=(l+r)>>1;
38     nw[0]=0;for(int i=l;i<=r;i++) nw[++nw[0]]=i;
39     sort(nw+1,nw+1+nw[0],cmp2);
40     for(int i=1;i<=nw[0];i++)
41     {
42         if(nw[i]<=mid&&t[nw[i]].id==0)
43         {
44             ad(t[nw[i]].c,1);
45         }
46         else if(nw[i]>mid&&t[nw[i]].id!=0)
47         {
48             t[nw[i]].ans+=query(t[nw[i]].c);
49         }
50     }
51     for(int i=l;i<=r;i++) if(i<=mid&&t[i].id==0) ad(t[i].c,-1);
52     ffind(l,mid);ffind(mid+1,r);
53 }
54
55 int main()
56 {
57     scanf("%d%d",&n,&q);
58     memset(ans,0,sizeof(ans));
59     for(int i=1;i<=n;i++)
60     {
61         int x;scanf("%d",&x);
62         w[i]=x;
63         add(i-x,i+x,1,0,0);
64     }ans[0]=0;
65     for(int i=1;i<=q;i++)
66     {
67         int x,y;
68         scanf("%s%d%d",s,&x,&y);
69         if(s[0]==‘Q‘)
70         {
71             add(x-w[x]+y,x+w[x]+y,i+1,++ans[0],1);
72             add(x-w[x]-y-1,x+w[x]-y-1,i+1,ans[0],1);
73             add(x-w[x]-y-1,x+w[x]+y,i+1,ans[0],-1);
74             add(x-w[x]+y,x+w[x]-y-1,i+1,ans[0],-1);
75         }
76         else
77         {
78             add(x-y,x+y,i+1,0,0);
79             w[x]=y;
80         }
81     }
82     sort(t+1,t+1+len,cmp);
83     ffind(1,len);
84     for(int i=1;i<=ans[0];i++) ans[i]=0;
85     for(int i=1;i<=len;i++) if(t[i].id!=0) ans[t[i].id]+=t[i].f*t[i].ans;
86     // for(int i=1;i<len;i++) printf("%d %d %d %d %d %d\n",t[i].a,t[i].b,t[i].c,t[i].id,t[i].f,t[i].ans);
87     for(int i=1;i<=ans[0];i++) printf("%d\n",ans[i]);
88     return 0;
89 }

认真地开了数组大小很久还是RE,干脆全部乘10了。。。

2017-03-26 16:40:39

时间: 2024-10-05 12:27:40

【BZOJ 4170】 4170: 极光 (CDQ分治)的相关文章

bzoj 1176 [Balkan2007]Mokia - CDQ分治 - 树状数组

Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小 接下来每行为一下三种输入之一(不包含引号): "1 x y a" "2 x1 y1 x2 y2" "3" 输入1:你需要把(x,y)(第x行第y列)的格子权值增加a 输入

BZOJ 1176 Mokia(cdq分治,解决一类在线查询问题)

题意:维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. 这题在bz是贵族题= =,没有链接了 解法:cdq分治,第一维是时间t,第二维是x,第三维是y:每个操作看作一个三维序(t, x, y):假设修改操作是(t, x, y),两个查询操作分别是(t1, x1, y1) 和 (t1, x2, y2):实际上就要问,有多少个修改操作,满足t<=t1,x1<=x&

BZOJ 1176 [Balkan2007]Mokia CDQ分治

题目大意: 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. POJ1195的加强版 没记错的话上午这题还没有中文题目描述的说0.0 好迅速 首先这题看到W就知道二维树状数组挂了 看到M就发现离散化了也搞不了 0.0 这题似乎是CDQ分治被发现之后第二个解决的题目...不过只有会员才知道的世界,今天反应过来刷刷... 修改和询问放在一起分治,一个询问拆分成4个,树状数组处

BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器,从第D+1天起,操作机器将为你产生每天G的收益.在你不再需要机器时,可以将机器卖掉,一次性获得R的收益.厂房里只能停留一台机器.不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台.在第N+1天,你必须卖掉手上的机器

bzoj 1176 Mokia(CDQ分治)

[题目链接]  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=96974 [题意] 定义查询操作与修改操作:1 x y z 为将格子(x,y)修改为z:2 x1 y1 x2 y2为查询以(x1,y1)为左上(x2,y2)为右下的子矩阵之和. [思路] cdq分治. 矩阵初始值都为s,所以先不考虑. 首先明确每一个修改操作都互不影响.然后把每一个对子矩阵的询问操作差分为对四个点的“前缀和”操作. 先把所有的操作按照x升序排列

BZOJ 2683 简单题 cdq分治+树状数组

题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后,二维的数据结构是显然不能过的,于是我们可能会考虑把一维排序之后另一位上数据结构什么的,然而cdq分治却能够很好的体现它的作用. 首先,对于每一个询问求和,显然是x在它左边的并且出现时间在它之前的所有的change对他可能会有影响. 我们按照x第一关键字,y第二关键字,操作第三关键字来排序所有的询问,然后在cdq的时候,每次递归处理左半区间,按照x动态的将y这一列的值加到树状数组里,来更新右半边的所有询问,注意这

BZOJ 2961 共点圆 CDQ分治+凸包

题目大意:给定平面,多次插入点和圆,每次插入点时询问当前插入的点是否在之前插入的所有圆中并且至少在一个圆中 直接用数据结构维护这些点和圆不是很好写,我们考虑CDQ分治 对于每层分治,我们需要对于[mid+1,r]中的每个点求出[l,mid]中是否所有的圆都覆盖了这个点 设点的坐标为(x0,y0),那么这个点在所有圆内必须满足对于所有的圆心(x,y),(x-x0)^2+(y-y0)^2<=x^2+y^2,即2*x*x0+2*y*y0>=x0^2+y0^2 我们发现上面的式子是一个半平面,斜率为-

bzoj 2683 简单题 cdq分治

题面 题目传送门 解法 可以离线,那么就是非常简单的cdq分治了 只要把询问拆成4个,然后就变成了一个三维偏序问题 时间复杂度:\(O(q\ log^2\ n)\) 代码 #include <bits/stdc++.h> #define int long long #define N 1000010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y

BZOJ 2683 简单题 ——CDQ分治

简单题 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define maxn 2000005 int sum[maxn]; void a

BZOJ 1176 Balkan 2007 Mokia CDQ分治

题目大意:有一些操作,给一个坐标代表的点加上一个数,和求出一个矩形中的所有数的和. 思路:一眼题,二位树状数组水过. ... .. . 哪里不对?W<=2000000.逗我?这n^2能开下? 这个时候CDQ神牛又来帮助我们了. 这个题应该算是CDQ分治的模板题了吧,简单分析一下,其实不难. 写这个题之前建议写一下BZOJ 1935 SHOI 2007 Tree 园丁的烦恼 树状数组这个题,是本题的简化版. 按照正常的解法,我们应该建立一个二位的数据结构,然后分别维护两维的信息.如果用动态开点的线