首页 > 代码库 > cogs 2320. [HZOI 2015]聪聪的世界题解

cogs 2320. [HZOI 2015]聪聪的世界题解

2320. [HZOI 2015]聪聪的世界

时间限制:6 s   内存限制:512 MB

【题目描述】

 

背景:

聪聪的性取向有问题。

题目描述:

聪聪遇到了一个难题:

给出一个序列a1…an,完成以下操作:

1  x 询问从x向左数第一个<ax的数;

2  x 询问从x向左数第一个>ax的数;

3  x 询问从x向右数第一个<ax的数;

4  x 询问从x向右数第一个>ax的数;

5  x y 交换ax与ay;

6  x y w 给ax…ay加上w;

7  x y w 给ax…ay减去w。

聪聪急切的想知道答案,因为他完成任务后就可以迎娶高富帅,出任CEO,走上人生巅峰,成为人生赢家!

请你帮帮他。

 

【输入格式】

 

第一行 n,m。

第二行 a1…an。

第三行到m+2行为以上七个操作。

 

【输出格式】

 

对于每个op>=1且op<=4输出一行表示答案,无解输出-1。

 

【样例输入】

 

5 5

8 2 0 0 9

1 2

5 1 3

7 1 3 1

4 2

1 1

 

【样例输出】

 

-1

7

-1

 

【提示】

 

10%  n,m<=10000

40%  n,m<=100000

100%  n,m<=1000000

对于所有输入的数保证在[0,10^9]范围内

 

  学长们出的题造的孽啊,貌似打法很多,我在这里只讲一下线段树解法。

  首先先膜拜一下     神利·代目   stdafx.h,两位学长,我是在他们的引导下想出的O(log)时间复杂度内完成前4个操作的。

  因为这四个操作本质一样,因此我们就只讲第一种操作。

  请读者自己先思考5~10分钟,看看能否相出log复杂度的前四种操作打法,提醒一下,从根节点边向下边二分不靠谱。

  开讲了,首先,线段树是一棵完全二叉树,因此它满足一个规律,兄弟节点的编号亦或1就是他自己,而它自己的编号/2就是他父亲的编号,因此我们完全可以用这个性质从下向上攀爬,再利用这个性质从上向下攀爬。

技术分享
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<cmath>
  8 using namespace std;
  9 long long n,m;
 10 struct no{
 11     long long left,right;
 12     long long mid,mn;
 13     long long mx,lazy;
 14 }node[4000004];
 15 long long a[1000005];
 16 long long dl[1000005];
 17 void build(long long left,long long right,long long x){
 18     node[x].left=left;
 19     node[x].right=right;
 20     if(left==right)
 21     {
 22         dl[left]=x;
 23         node[x].mn=node[x].mx=a[left];
 24         return;
 25     }
 26     long long mid=(left+right)/2;
 27     node[x].mid=mid;
 28     build(left,mid,2*x);
 29     build(mid+1,right,2*x+1);
 30     node[x].mx=max(node[2*x].mx,node[2*x+1].mx);
 31     node[x].mn=min(node[x*2].mn,node[2*x+1].mn);
 32 }
 33 void pushdown(long long x){
 34     if(node[x].lazy)
 35     {
 36         node[2*x].lazy+=node[x].lazy;
 37         node[2*x+1].lazy+=node[x].lazy;
 38         node[2*x].mx+=node[x].lazy;
 39         node[2*x+1].mx+=node[x].lazy;
 40         node[x*2].mn+=node[x].lazy;
 41         node[2*x+1].mn+=node[x].lazy;
 42         node[x].lazy=0;
 43     }
 44 }
 45 long long get(long long left,long long right,long long x){
 46     if(node[x].left==node[x].right)
 47     {
 48         return node[x].mx;
 49     }
 50     pushdown(x);
 51     long long mid=node[x].mid;
 52     if(right<=node[x].mid)
 53         return get(left,right,2*x);
 54     else
 55         return get(left,right,2*x+1);
 56 }
 57 void change(long long left,long long right,long long x,long long z){
 58     if(node[x].left==node[x].right)
 59     {
 60         node[x].mn=z;
 61         node[x].mx=z;
 62         return;
 63     }
 64     pushdown(x);
 65     long long mid=node[x].mid;
 66     if(right<=node[x].mid)
 67         change(left,right,2*x,z);
 68     else
 69         change(left,right,2*x+1,z);
 70     node[x].mx=max(node[2*x].mx,node[2*x+1].mx);
 71     node[x].mn=min(node[2*x].mn,node[1+2*x].mn);
 72 }
 73 void add(long long left,long long right,long long x,long long z){
 74     if(node[x].left==left&&node[x].right==right)
 75     {
 76         node[x].mx+=z;
 77         node[x].mn+=z;
 78         node[x].lazy+=z;
 79         return;
 80     }
 81     pushdown(x);
 82     long long mid=node[x].mid;
 83     if(right<=mid)
 84         add(left,right,2*x,z);
 85     else if(left>mid)
 86         add(left,right,2*x+1,z);
 87     else
 88         add(left,mid,2*x,z),add(mid+1,right,2*x+1,z);
 89     node[x].mx=max(node[2*x].mx,node[2*x+1].mx);
 90     node[x].mn=min(node[x*2].mn,node[2*x+1].mn);
 91 }
 92 long long que_ls(long long x,long long z,long long buf){
 93     if(node[x].left==node[x].right)
 94         return node[x].left;
 95     if(node[2*x+1].mn+buf+node[x].lazy<z)
 96         return que_ls(2*x+1,z,buf+node[x].lazy);
 97     else
 98         return que_ls(2*x,z,buf+node[x].lazy);
 99 }
100 long long get_ls(long long x,long long z){
101     if(x==1)
102         return -1;
103     if(!(x%2))
104         return get_ls(x/2,z+node[x].lazy);
105     else
106     {
107         if(z+node[x].lazy>node[x^1].mn)
108             return que_ls(x^1,z+node[x].lazy,0);
109         else
110             return get_ls(x/2,z+node[x].lazy);
111     }
112 }
113 long long que_lb(long long x,long long z,long long buf){
114     if(node[x].left==node[x].right)
115         return node[x].left;
116     if(node[2*x+1].mx+buf+node[x].lazy>z)
117         return que_lb(x*2+1,z,buf+node[x].lazy);
118     else
119         return que_lb(x*2,z,buf+node[x].lazy);
120 }
121 long long get_lb(long long x,long long z){
122     if(x==1)
123         return -1;
124     if(!(x%2))
125         return get_lb(x/2,z+node[x].lazy);
126     else
127     {
128         if(z+node[x].lazy<node[x^1].mx)
129             return que_lb(x^1,z+node[x].lazy,0);
130         else
131             return get_lb(x/2,z+node[x].lazy);
132     }
133 }
134 long long que_rs(long long x,long long z,long long buf){
135     if(node[x].left==node[x].right)
136         return node[x].left;
137     if(node[2*x].mn+buf+node[x].lazy<z)
138         return que_rs(x*2,z,buf+node[x].lazy);
139     else
140         return que_rs(x*2+1,z,buf+node[x].lazy);
141 }
142 long long get_rs(long long x,long long z){
143     if(x==1)
144         return -1;
145     if(x%2)
146         return get_rs(x/2,z+node[x].lazy);
147     else
148     {
149         if(z+node[x].lazy>node[x^1].mn)
150             return que_rs(x^1,z+node[x].lazy,0);
151         else
152             return get_rs(x/2,z+node[x].lazy);
153     }
154 }
155 long long que_rb(long long x,long long z,long long buf){
156     if(node[x].left==node[x].right)
157         return node[x].left;
158     if(node[x*2].mx+buf+node[x].lazy>z)
159         return que_rb(x*2,z,buf+node[x].lazy);
160     else
161         return que_rb(x*2+1,z,buf+node[x].lazy);
162 }
163 long long get_rb(long long x,long long z){
164     if(x==1)
165         return -1;
166     if(x%2)
167         return get_rb(x/2,z+node[x].lazy);
168     else
169     {
170         if(z+node[x].lazy<node[x^1].mx)
171             return que_rb(x^1,z+node[x].lazy,0);
172         else
173             return get_rb(x/2,z+node[x].lazy);
174     }
175 }
176 int main(){
177     freopen("ccsworld.in","r",stdin);
178     freopen("ccsworld.out","w",stdout);
179     scanf("%lld%lld",&n,&m);
180     for(int i=1;i<=n;i++)
181         scanf("%lld",&a[i]);
182     build(1,n,1);
183     for(int i=1;i<=m;i++)
184     {
185         long long tt;
186         scanf("%lld",&tt);
187         if(tt==1)
188         {
189             long long x;
190             scanf("%lld",&x);
191             long long y=get_ls(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
192             if(y!=-1) printf("%lld\n",get(y,y,1));
193             else printf("%lld\n",y);
194         }
195         if(tt==2)
196         {
197             long long x;
198             scanf("%lld",&x);
199             long long y=get_lb(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
200             if(y!=-1) printf("%lld\n",get(y,y,1));
201             else printf("%lld\n",y);
202         }
203         if(tt==3)
204         {
205             long long x;
206             scanf("%lld",&x);
207             long long y=get_rs(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
208             if(y!=-1) printf("%lld\n",get(y,y,1));
209             else printf("%lld\n",y);
210         }
211         if(tt==4)
212         {
213             long long x;
214             scanf("%lld",&x);
215             long long y=get_rb(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
216             if(y!=-1) printf("%lld\n",get(y,y,1));
217             else  printf("%lld\n",y);
218         }
219         if(tt==5)
220         {
221             long long x,y;
222             scanf("%lld%lld",&x,&y);
223             long long xx,yy;
224             xx=get(x,x,1);
225             yy=get(y,y,1);
226             change(x,x,1,yy);
227             change(y,y,1,xx);
228         }
229         if(tt==6)
230         {
231             long long x,y,z;
232             scanf("%lld%lld%lld",&x,&y,&z);
233             add(x,y,1,z);
234         }
235         if(tt==7)
236         {
237             long long x,y,z;
238             scanf("%lld%lld%lld",&x,&y,&z);
239             add(x,y,1,0-z);
240         }
241     }
242     //while(1);
243     return 0;
244 }
一份长达5k的代码,慎入

 

  因此,我们大可开个数组存下每个叶节点的编号,便于查找,然后就从我们询问的叶节点向上查找,如果当前位置为右子树,那么就看一下他的兄弟的最小值是否比它小,如果不是,那么继续向上爬,如果是,我们就从他的兄弟节点向下爬。如果当前位置是左子树,我们就得接着向上爬了,他的右子树是不满足条件的,因为本题有区间操作,所以lazy数组就成了一个让人头痛的东西,让我们来慢慢分析。

  首先我向上爬时路径上的lazy是影响的,因为我们都是从叶节点向上爬,因此叶节点的数值是最晚更新的,因此向上爬的lazy是一定要加上的,那么有人可能回去问了,有可能之前还有区间操作只是没下放呢,这就不必担心了,因为如果他没得到lazy,他的兄弟一定也没得到,两者抵消。

  其次,向下爬的lazy也是会影响的,因为我们要的是最靠近x的叶节点,因此我们应采用先右后左的方法,如果右子树的最小值比上面那步传下来的参数小,就搜右子树,左子树就不必管了,而lazy也是需要一直跟着下放,原理见上。

  我们最终传回来的值并不是当前节点的值,因为上面的值可能还没传下来,因此我们传的应当是它的位置,再从根节点向下搞也就是单点查询了。

  至于其他三个操作,请读者自己思考并实现。

  打完代码后提交,全WA,被QTY2001神犇提醒,没开long long。交完就A了,没啥坑点,主要是码力,被教练员吐槽代码能力弱的我都能在一小时之内搞掉,这道题的难度也是没谁了。这或许就是他只有3星的原因吧。

 

cogs 2320. [HZOI 2015]聪聪的世界题解