BZOJ4170:极光(CDQ分治)

Description

"若是万一琪露诺(俗称rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她。对方表现出兴趣的话,那就慢慢地反问。在她考虑答案的时候,趁机逃吧。就算是很简单的问题,她一定也答不上来。"--《上古之魔书》
天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:2个位置的graze值为两者位置差与数值差的和: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, 修改操作数<=60000, 询问操作数<=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

Solution

设一个点的坐标为$(x,a[x])$,然后发现$graze(x,i) \leq k$的点就是曼哈顿距离到$x$点距离小于等于$k$的点。
但这玩意儿好像是个斜着的正方形?咋矩形求和啊……话说我是不是之前做$K-D~Tree$的时候看过一个什么曼哈顿转切比雪夫的?
曼哈顿$(x,a[x])->$切比雪夫$(x+a[x],x-a[x])$,切比雪夫计算两点距离好像是横纵坐标差的$max$?
这样转下切比雪夫然后一个点要查询的点不就成了一个正着的正方形内的点的个数了么……
这样好像就可以矩形求和了啊……发现那个什么鬼畜历史版本就是扯淡?不就是加入一个点么…

$PS:$此题数据范围描述是假的!

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define N (1000009)
 5 using namespace std;
 6 
 7 struct Que{int x,y,opt,v;}Q[N],tmp[N];
 8 int n,m,q_num,cnt,a[N],c[N],ans[N];
 9 char opt[10];
10 
11 inline int read()
12 {
13     int x=0,w=1; char c=getchar();
14     while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();}
15     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
16     return x*w;
17 }
18 
19 void Update(int x,int k)
20 {
21     for (; x<=1e6; x+=(x&-x)) c[x]+=k;
22 }
23 
24 int Query(int x)
25 {
26     int ans=0;
27     for (; x; x-=(x&-x)) ans+=c[x];
28     return ans;
29 }
30 
31 void CDQ(int l,int r)
32 {
33     if (l==r) return;
34     int mid=(l+r)>>1;
35     CDQ(l,mid); CDQ(mid+1,r);
36     int i=l,j=mid+1,k=l-1;
37     while (i<=mid || j<=r)
38         if (j>r || i<=mid && (Q[i].x<Q[j].x || Q[i].x==Q[j].x && Q[i].opt<Q[j].opt))
39         {
40             if (Q[i].opt==1) Update(Q[i].y,1);
41             tmp[++k]=Q[i]; ++i;
42         }
43         else
44         {
45             if (Q[j].opt==2)
46             {
47                 if (Q[j].v>0) ans[Q[j].v]+=Query(Q[j].y);
48                 else ans[-Q[j].v]-=Query(Q[j].y);
49             }
50             tmp[++k]=Q[j]; ++j;
51         }
52     for (int i=l; i<=mid; ++i) if (Q[i].opt==1) Update(Q[i].y,-1);
53     for (int i=l; i<=r; ++i) Q[i]=tmp[i];
54 }
55 
56 int main()
57 {
58     n=read(); m=read();
59     for (int i=1; i<=n; ++i)
60     {
61         a[i]=read();
62         Q[++q_num]=(Que){i+a[i],i-a[i],1,1};
63     }
64     for (int i=1; i<=m; ++i)
65     {
66         scanf("%s",opt); int x=read(),k=read();
67         if (opt[0]=='M') a[x]=k, Q[++q_num]=(Que){x+k,x-k,1,1};
68         else
69         {
70             ++cnt;
71             Q[++q_num]=(Que){x+a[x]+k,x-a[x]+k,2,cnt};
72             Q[++q_num]=(Que){x+a[x]-k-1,x-a[x]-k-1,2,cnt};
73             Q[++q_num]=(Que){x+a[x]-k-1,x-a[x]+k,2,-cnt};
74             Q[++q_num]=(Que){x+a[x]+k,x-a[x]-k-1,2,-cnt};
75         }
76     }
77     for (int i=1; i<=q_num; ++i) Q[i].x+=500000, Q[i].y+=500000;
78     CDQ(1,q_num);
79     for (int i=1; i<=cnt; ++i) printf("%d\n",ans[i]);
80 }
posted @ 2019-03-07 10:23  Refun  阅读(271)  评论(0编辑  收藏  举报