8.5题解

明天要考试了,我今天竟然异常颓废,我大概已经是个废oier了,不过lrd学长的博客真吸引人,明天考试,今天颓废,会不会rp--遭报应啊,希望不会吧,接下来,进正题

T1

我以为真的会有什么矩阵之类的,果然出题人都是大骗纸,竟然出个数学题欺负我,垃圾数学毁我青春,考场上一开始想到一个觉得自己稳了的算法,结果是假的,最后交了暴力?pa大哥20分钟AC?我垃圾,其实就是个推式子的题,然而我考后依旧推了一个小时,疯狂%%%%%$starsing$,其实还是那种循序渐进一步步来的,肯定暴力可以想到$ans=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}((i-1)*m+j)*h[i]*l[j]$,然而我并没有,垃圾只会暴力修改,O(nm)求和,解释一下$h[i]$代表第$i$行累计被乘了多少倍,显然那些操作的先后顺序对答案没影响,大概真的很显然?$l[i]$同理,代表第$j$列累计被乘了多少倍,然后我们就开始了疯狂手推式子,我先是给他搞成了这个样子,$ans=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}(i-1)*m*h[i]*l[j]+\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}j*h[i]*l[j]$,然后我的思路戛然而止,然而由于大家都说他水,就没好意思问,自己又随便写写画画,发现对于前一项的每个$i$都乘上了所有的$j$,也就是对于每个$i$乘上了$\sum\limits_{j=1}^{m}l[j]$,那同理对于后一项中的每个$j$也都乘上了$\sum\limits_{i=1}^{n}h[i]$,那我们求一下和,就可以愉快的以O(n+m)的复杂度A掉这道题了,不过好像据说我是推麻烦了?

 1 #include<cstdio>
 2 #include<iostream>
 3 #define maxn 1000100
 4 #define ll long long
 5 using namespace std;
 6 const long long mod=1e9+7;
 7 int k;
 8 ll n,m,ans,sum1,sum2;
 9 ll hang[maxn]/*每行的贡献*/,lie[maxn]/*每列的贡献*/;
10 int main()
11 {
12 //    freopen("1.in","r",stdin);
13     scanf("%lld%lld%d",&n,&m,&k);
14     for(int i=1;i<=n;++i)  hang[i]=1;
15     for(int i=1;i<=m;++i)  lie[i]=1;
16     while(k--)
17     {
18         char ddd[3];  ll x,y;  scanf("%s%lld%lld",ddd,&x,&y);
19         if(ddd[0]=='R')  hang[x]=(hang[x]*y)%mod;
20         else  lie[x]=(lie[x]*y)%mod;
21     }
22     for(int i=1;i<=n;++i)  sum1=(sum1+hang[i])%mod;
23     for(int i=1;i<=m;++i)  sum2=(sum2+lie[i])%mod;
24     for(int i=1;i<=n;++i)
25             ans=(ans+((((((i-1)*m)%mod)*hang[i])%mod)*sum2)%mod)%mod;
26     for(int i=1;i<=m;++i)  ans=(ans+(((i*lie[i])%mod)*sum1)%mod)%mod;
27     printf("%lld\n",ans);
28     return 0;
29 }    
View Code

 

T2

今天刚A掉,重构了3次,每次代码都长达200行?我心痛啊,我死了

算法一:模拟

虽然说他叫模拟,但实际上,这是正解,至于我为什么要叫它模拟,因为他就是个模拟,啊呸,对模拟的优化

预处理

我们可以把以格子为单位的跳动,变为以m格为单位的跳动,大概就是跑一圈的意思,我们设$jump[i]$,代表从第一列第$i$行出发,跳$m$步,回到第一列第$jump[i]$行,这个东西,暴力O(mn)跑一发,顺带可以再处理个循环节,他们打的bfs,然鹅我不会,所以zz的打了tarjan?打板子好开心,啥都不用想,处理循环节,其实就是给$i->jump[i]$连边,那对于建出的图,循环节一定是个环,所以,tarjan真爽,记录一下环中一共几个点,给环中的点打标记就好了,不过可能有多个环,所以还是判一下吧

move

这题只要分想高一点,就需要搞循环节,不过这个东西看到$k\leq1e9$,应该就可以想到了,不过我嫌太麻烦就没打,不过正解还是逃不过,首先,由于我们记录的$jump$是从第一列开始的,所以我们先暴力跳到第一列,然后第一列的那个点不在循环节上怎么办?暴力跳$jump$,直到自己到达循环节,然后原地让剩余步数对$m*$环中的点数取模,当然还在原地啦,然后剩下的步数就不够跳循环节的了,那我们就先跳暴力跳$jump$,跳到剩余步数小于$m$,然后暴力单格跳就ok了

change

我死在这了,实在是不想实现了,觉得模拟会搞死我,然后就重构了,所以指路山大附dalao

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 using namespace std;
  5 #define Re register
  6 int n,m,Q;
  7 int a[2100][2100],v[2100],st[2100],inst[2100],is_c[2100],jump[2100],num,la;
  8 int px=0,py=0;
  9 char opt[10];
 10 inline int read(){
 11     register int ret;
 12     register char r;
 13     while(r=getchar(),r<'0'||r>'9');ret=r-48;
 14     while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48;
 15     return ret;
 16 }
 17 inline int dfs1(int x,int y){
 18     int xup=(x-1+n)%n,xdown=(x+1+n)%n;
 19     if(y==m-1) return a[x][0]>a[xup][0]?(a[x][0]>a[xdown][0]?x:xdown):(a[xup][0]>a[xdown][0]?xup:xdown);
 20     return a[x][y+1]>a[xup][y+1]?(a[x][y+1]>a[xdown][y+1]?dfs1(x,y+1):dfs1(xdown,y+1)):(a[xup][y+1]>a[xdown][y+1]?dfs1(xup,y+1):dfs1(xdown,y+1));
 21 }
 22 inline void walk(int &c,int opt){
 23     if(opt==1){
 24             while(py!=0&&c){
 25                 c--;
 26                 py=(py+1)%m;
 27                 int xup=(px-1+n)%n,xdown=(px+1+n)%n;
 28                 if(a[px][py]>a[xup][py]&&a[px][py]>a[xdown][py]) px=px;
 29                 else if(a[xup][py]>a[px][py]&&a[xup][py]>a[xdown][py]) px=xup;
 30                 else if(a[xdown][py]>a[px][py]&&a[xdown][py]>a[xup][py]) px=xdown;  
 31             }
 32             while(!is_c[px]&&c>=m){
 33                 c-=m;
 34                 px=jump[px];
 35             }
 36     }
 37     else{
 38         while(c>=m){
 39             c-=m;
 40             px=jump[px];
 41         }
 42         while(c){
 43             c--;
 44             py=(py+1)%m;
 45             int xup=(px-1+n)%n,xdown=(px+1+n)%n;
 46             if(a[px][py]>a[xup][py]&&a[px][py]>a[xdown][py]) px=px;
 47             else if(a[xup][py]>a[px][py]&&a[xup][py]>a[xdown][py]) px=xup;
 48             else if(a[xdown][py]>a[px][py]&&a[xdown][py]>a[xup][py]) px=xdown;
 49         }
 50     }
 51 }
 52 inline void dfs2(int x){
 53     v[x]=inst[x]=1;
 54     st[++st[0]]=x;
 55     if(inst[jump[x]]){
 56         int y;
 57         num=0;
 58         do{
 59             y=st[st[0]--];
 60             inst[y]=0;
 61             is_c[y]=1;
 62             num+=m;
 63         }while(y!=jump[x]);
 64     }
 65     else if(!v[jump[x]]) dfs2(jump[x]);
 66     inst[x]=0;
 67 }
 68 int update1(int x,int y){
 69   //  cout<<"d"<<endl;
 70     if(y==0) return x;
 71     int xu1=(x-1+n)%n,xd1=(x+1+n)%n;
 72     int xu2=(xu1-1+n)%n,xd2=(xd1+1+n)%n;
 73     int l=-1;
 74     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xu2][y]) l=update1(xu1,y-1);
 75     if(l!=-1) return l;
 76     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xd1][y]) l=update1(x,y-1);
 77     if(l!=-1) return l;
 78     if(a[x][y]>a[xd1][y]&&a[x][y]>a[xd2][y]) l=update1(xd1,y-1);
 79     return l;
 80 }
 81 int update2(int x,int y){
 82 //    cout<<"f"<<endl;
 83     if(y==0) return x;
 84     int xu1=(x-1+n)%n,xd1=(x+1+n)%n;
 85     int xu2=(xu1-1+n)%n,xd2=(xd1+1+n)%n;
 86     int r=-1;
 87     if(a[x][y]>a[xd1][y]&&a[x][y]>a[xd2][y]) r=update2(xd1,y-1);
 88     if(r!=-1) return r;
 89     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xd1][y]) r=update2(x,y-1);
 90     if(r!=-1) return r;
 91     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xu2][y]) r=update2(xu1,y-1);
 92     return r;
 93 }
 94 inline void update(int x,int y,int to){
 95     if(y==0){
 96         jump[x]=to;
 97         return;    
 98     }
 99     int xu1=(x-1+n)%n,xd1=(x+1+n)%n;
100     int xu2=(xu1-1+n)%n,xd2=(xd1+1+n)%n;
101     int l=-1,r=-1;
102     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xu2][y]){
103         l=update1(xu1,y-1);
104     }
105     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xd1][y]){
106         if(l==-1) l=update1(x,y-1);
107     }
108     if(a[x][y]>a[xd1][y]&&a[x][y]>a[xd2][y]){
109         if(l==-1) l=update1(xd1,y-1);
110     }
111     
112     
113     
114     if(a[x][y]>a[xd1][y]&&a[x][y]>a[xd2][y]){
115         r=update2(xd1,y-1);
116     }   
117     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xd1][y]){
118         if(r==-1) r=update2(x,y-1);
119     }
120     if(a[x][y]>a[xu1][y]&&a[x][y]>a[xu2][y]){
121        if(r==-1) r=update2(xu1,y-1);    
122     }
123     
124     
125     
126     if(l==-1) return;
127     if(l>r){
128         for(int i=l;i<n;i++) jump[i]=to;
129         for(int i=0;i<=r;i++) jump[i]=to;
130     }
131     else for(int i=l;i<=r;i++) jump[i]=to;
132     
133 } 
134 inline void change(int x,int y){
135     int xu1=(x-1+n)%n,xd1=(x+1+n)%n;
136     int xu2=(xu1-1+n)%n,xd2=(xd1+1+n)%n;
137     int ny=(y-1+m)%m;
138     int to;
139     if(y!=0) to=dfs1(x,y);
140     else to=x;
141     int toup1,toup2,todown1,todown2;
142     if(y==0){
143         toup1=xu1,toup2=xu2;
144         todown1=xd1,todown2=xd2;
145     }
146     else{
147         toup1=dfs1(xu1,y);
148         toup2=dfs1(xu2,y);
149         todown1=dfs1(xd1,y);
150         todown2=dfs1(xd2,y);
151     }
152     if(a[xu1][y]>la||a[xu2][y]>la){
153         if(a[x][y]>a[xu1][y]&&a[x][y]>a[xu2][y]) update(xu1,ny,to);
154     }
155     else if(a[xu1][y]<la&&a[xu2][y]<la){
156         if(a[x][y]<a[xu1][y]||a[x][y]<a[xu2][y]){
157             update(xu1,ny,a[xu1][y]>a[xu2][y]?toup1:toup2);
158         }
159     }
160     if(a[xu1][y]>la||a[xd1][y]>la){
161         if(a[x][y]>a[xu1][y]&&a[x][y]>a[xd1][y]) update(x,ny,to);
162     }
163     else if(a[xu1][y]<la&&a[xd1][y]<la){
164         if(a[x][y]<a[xu1][y]||a[x][y]<a[xd1][y]){
165             update(x,ny,a[xu1][y]>a[xd1][y]?toup1:todown1);
166         }
167     }
168     if(a[xd1][y]>la||a[xd2][y]>la){
169         if(a[x][y]>a[xd1][y]&&a[x][y]>a[xd2][y]) update(xd1,ny,to);
170     }
171     else if(a[xd1][y]<la&&a[xd2][y]<la){
172         if(a[x][y]<a[xd1][y]||a[x][y]<a[xd2][y]){
173             update(xd1,ny,a[xd1][y]>a[xd2][y]?todown1:todown2);
174         }
175     }
176 }
177 int main(){
178     n=read(),m=read();
179     for(Re int i=0;i<n;i++){
180         for(Re int j=0;j<m;j++){
181             a[i][j]=read();
182         }
183     }
184     for(Re int i=0;i<n;i++){
185         jump[i]=dfs1(i,0);
186     }
187     for(Re int i=0;i<n;i++)
188         if(!v[i])
189             dfs2(i);
190     scanf("%d",&Q);
191     int x,y,c;
192     while(Q--){
193         scanf("%s",opt);
194         if(opt[0]=='m'){
195             c=read();
196             walk(c,1);
197             c%=num;
198             walk(c,0);
199             printf("%d %d\n",px+1,py+1);
200         }
201         else{
202             x=read(),y=read(),c=read();
203             x--,y--;
204             la=a[x][y];
205             a[x][y]=c;
206             change(x,y);
207             for(int i=0;i<n;i++) v[i]=is_c[i]=0;
208             st[0]=0;
209             for(int i=0;i<n;i++)
210                 if(!v[i])
211                     dfs2(i);
212         }
213     }
214 }
没打完就弃了,代码来自Lockey

 

算法二:线段树+类似矩阵快速幂的神秘力量?

emm,今天重构的,及其好写,比200多行模拟爽多了,当然思路也要推翻重新来过

我们用线段树叶子节点维护每一列的每一行跳到下一列的哪一行上,以列为下标,线段树里开数组,对于叶子节点我们只能跳一格,但是对于非叶子节点我们就可以好几格好几格的跳了,类似于你可以从$a->b$,再从$b->c$,那线段树$update$之后,你就可以从$a->c$了,查询的时候就先处理出来跳一圈的跳跃路线?反正就是让他跳一圈,然后我们就可以愉快的快速幂了,有几圈就几次幂,剩下多余的步数还是暴力跳了

change比模拟让人开心多了,我们发现改一个点,只会影响他的前一列,由于我们懒得分类讨论,所以直接把前一列全部暴力修改,然后剩下的交给$update$就可以了,一个小点就是第一列的前一列是第$n$列,不是第零列,打题请保持清醒,每次都死在zz点上

  1 //线段树下标为每一列,每一列里记录n行中的每一行到达下一列的哪一行
  2 //在上传时,从l跳到mid,再从mid跳到r,直接就跳一下
  3 //查询答案时先初始化一个从自己跳到自己的ans,跳一整圈,然后给这个跳了一整圈之后的ans直接k/m次幂
  4 //剩下几步暴力跳
  5 //change的时候直接把要修改的点的前一列全部暴力修改,之后直接update即可
  6 #include<iostream>
  7 #include<cstdio>
  8 #define maxn 2010
  9 using namespace std;
 10 int n,m,q,h,z,x=1,y=1;
 11 int a[maxn][maxn];
 12 struct node{
 13     int zuo,you;
 14     int hang[maxn];
 15     void mem()
 16     {
 17         for(int i=1;i<=n;++i)  hang[i]=i;
 18     }
 19 }lie[maxn*4],ans;
 20 void bl()
 21 {
 22     if(h==1&&z==m)
 23     {
 24         int ls1=a[n][1],ls2=a[1][1],ls3=a[2][1];
 25         int zd=max(ls1,max(ls2,ls3));
 26         if(ls1==zd)  h=n;
 27         else if(ls2==zd)  h=1;
 28         else  h=2;
 29     }
 30     else if(h==n&&z==m)
 31     {
 32         int ls1=a[n-1][1],ls2=a[n][1],ls3=a[1][1];
 33         int zd=max(ls1,max(ls2,ls3));
 34         if(ls1==zd)  h=n-1;
 35         else if(ls2==zd)  h=n;
 36         else  h=1;
 37     }
 38     else if(z==m)
 39     {
 40         int ls1=a[h-1][1],ls2=a[h][1],ls3=a[h+1][1];
 41         int zd=max(ls1,max(ls2,ls3));
 42         if(ls1==zd)  h--;
 43         else if(ls3==zd)  h++;
 44     }
 45     else if(h==1)
 46     {
 47         int ls1=a[n][z+1],ls2=a[1][z+1],ls3=a[2][z+1];
 48         int zd=max(ls1,max(ls2,ls3));
 49         if(ls1==zd)  h=n;
 50         else if(ls2==zd)  h=1;
 51         else  h=2;
 52     }
 53     else if(h==n)
 54     {
 55         int ls1=a[n-1][z+1],ls2=a[n][z+1],ls3=a[1][z+1];
 56         int zd=max(ls1,max(ls2,ls3));
 57         if(ls1==zd)  h=n-1;
 58         else if(ls2==zd)  h=n;
 59         else  h=1;
 60     }
 61     else
 62     {
 63         int ls1=a[h-1][z+1],ls2=a[h][z+1],ls3=a[h+1][z+1];
 64         int zd=max(ls1,max(ls2,ls3));
 65         if(ls1==zd)  h--;
 66         else if(ls3==zd)  h++;
 67     }
 68 }
 69 node cheng(node a,node b)
 70 {
 71     node sum;  sum.mem();
 72     for(int i=1;i<=n;++i)  sum.hang[i]=b.hang[a.hang[i]];
 73     return sum;
 74 }
 75 node ksm(node a,int x)
 76 {
 77     node sum;  sum.mem();
 78     while(x)
 79     {
 80         if(x&1)  sum=cheng(sum,a);
 81         a=cheng(a,a);  x=x>>1;
 82     }
 83     return sum;
 84 }
 85 void update(int f)
 86 {
 87     for(int i=1;i<=n;++i)  lie[f].hang[i]=lie[2*f+1].hang[lie[2*f].hang[i]];
 88 }
 89 void build(int f,int l,int r)
 90 {
 91     lie[f].zuo=l;  lie[f].you=r;
 92     if(l==r)
 93     {
 94         for(int i=1;i<=n;++i)  {h=i;  z=l;  bl();  lie[f].hang[i]=h;}
 95         return ;
 96     }
 97     int mid=(l+r)>>1;
 98     build(2*f,l,mid);  build(2*f+1,mid+1,r);
 99     update(f);
100 }
101 void quary(int f,int l,int r)
102 {
103     if(lie[f].zuo>=l&&lie[f].you<=r)  {ans=cheng(ans,lie[f]);  return ;}
104     int mid=(lie[f].zuo+lie[f].you)>>1;
105     if(l<=mid)  quary(2*f,l,r);
106     if(r>mid)  quary(2*f+1,l,r);
107 }
108 void change(int f,int pos)
109 {
110     if(lie[f].zuo==lie[f].you&&lie[f].zuo==pos)
111     {
112         for(int i=1;i<=n;++i)  {h=i;  z=pos;  bl();  lie[f].hang[i]=h;}
113         return ;
114     }
115     int mid=(lie[f].zuo+lie[f].you)>>1;
116     if(pos<=mid)  change(2*f,pos);
117     else  change(2*f+1,pos);
118     update(f);
119 }
120 int main()
121 {
122 //    freopen("jump0.in","r",stdin);
123     scanf("%d%d",&n,&m);
124     for(int i=1;i<=n;++i)
125         for(int j=1;j<=m;++j)  scanf("%d",&a[i][j]);
126     build(1,1,m);
127     scanf("%d",&q);
128     while(q--)
129     {
130         char ddd[20];  scanf("%s",ddd);
131         if(ddd[0]=='m')
132         {
133             int k;  scanf("%d",&k);
134             ans.mem();
135             quary(1,y,m);
136             if(y!=1)  quary(1,1,y-1);
137             ans=ksm(ans,k/m);
138             if(y+k%m-1<=m)  quary(1,y,y+k%m-1);
139             else  {quary(1,y,m);  quary(1,1,k%m-m+y-1);}
140             x=ans.hang[x];  y=(y+k%m)%m;
141             if(!y)  y=m;
142             printf("%d %d\n",x,y);
143         }
144         else
145         {
146             int r,s,t;  scanf("%d%d%d",&r,&s,&t);  a[r][s]=t;
147             if(s!=1)  change(1,s-1);
148             else  change(1,m);
149         }
150     }
151     return 0;
152 }
码量可接受

T3[洛谷P4747]

考试打了个复杂度不可预估的线段树,竟然水到了80分,全场并列最高分,惊讶,考后大力卡常,把初始化和查询均为O(logn)的线段树,改成了初始化同水平,查询O(1)的ST表,学了一发ST表,才发现学$RMQ$和倍增的时候好像学过?我一定是失忆了,成功水到92,然后我就止步于此去打正解了,我才不会说我一下午都在疯狂卡常,skyh分块+ST表,暴力碾标算,我只能疯狂%%%%,正解看了很久,最后是被讲明白的,果然还太弱

线段树又要出场了,让我们掌声欢迎,首先我们发现这个优美序列有几个优美的性质,首先是做了奇袭都应该想到而我没想到的区间$\max$-区间$\min=r-l$,然而他好像没什么大用,然后就是两个不相互包含的合法区间的交集也是个合法区间,感性理解+理性证明你会发现很对,毕竟对于那个交集,如果他不合法,但他和区间其他数可以构成合法序列,那么中间的数就出现在了区间剩余部分中,可这个数只有一个,区间却有两个,显然不对,那我们的答案应该就是第一个右端点在所求区间右端点右侧且可以包住整个所求区间的区间,有点绕,可以停下来稍微理解一下,那我们可以以O(n)的复杂度枚举右端点,那我们的任务就变成了确定左端点,我们可以发现合法区间还有一个并不神奇的性质,我们规定相邻两个数构成一个点对,像(2,3)(6,7)这种样子的,那么对于一个合法区间$[l,r]$设区间中的点对个数为$sum$,友情提醒(4,5)(5,4)算一个,我们可以只算这个点和他之前的点构成的点对个数,这样就不会重复了,那么$l+sum=r$,自己画去,挺显然的,那我们只需要扫描当前枚举的右端点左面的点,看看是否满足,关于点对的计算,假设当前枚举的点为$i$,那可以和他构成点对的只有$a[i]-1$和$a[i]+1$两个点,看一下这两个点是否在$i$的前面,如果在就贡献点对,给$[1,pos]$之间的每个点到i区间中的点对数目++就可以了,可是O(n)扫,当然就死了,我们还会发现${l+sum}\leq{r}$,那我们完全可以线段树维护区间$l+sum$的最值,因为这个值只有可能不断变大,所以这样维护可行,对于回答,当我们扫描到一个右端点,我们就把询问区间右端点是这个点的区间扔进根堆里,按$l$降序$r$升序排列,每次看堆顶是否可以回答,可以就回答,不可以就结束回答,继续向后扫描,就结束了

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<vector>
  5 #define maxn 100100
  6 using namespace std;
  7 struct tree{
  8     int zuo,you,num,pos,lan;
  9 }xds[maxn*4];
 10 struct node{
 11     int l,r,id;
 12 }q[maxn];
 13 bool operator < (const node &a,const node &b)
 14 {
 15     if(a.l!=b.l)  return a.l<b.l;
 16     return a.r>b.r;
 17 }
 18 int n,m,ans;
 19 int a[maxn],pos[maxn],ansl[maxn],ansr[maxn];
 20 priority_queue <node> quary;
 21 vector <node> qua[maxn];
 22 inline int read()
 23 {
 24     int e=0,f=1;  char ch=getchar();
 25     while(ch<'0'||ch>'9')
 26     {
 27         if(ch=='-')  f=-1;
 28         ch=getchar();
 29     }
 30     while(ch>='0'&&ch<='9')  {e=(e<<3)+(e<<1)+(ch^48);  ch=getchar();}
 31     return e*f;
 32 }
 33 void up(int f)
 34 {
 35     if(xds[2*f].num>xds[2*f+1].num)
 36     {
 37         xds[f].num=xds[2*f].num;  xds[f].pos=xds[2*f].pos;
 38     }
 39     else  {xds[f].num=xds[2*f+1].num;  xds[f].pos=xds[2*f+1].pos;}
 40 }
 41 void down(int f)
 42 {
 43     if(!xds[f].lan)  return ;
 44     xds[2*f].num+=xds[f].lan;  xds[2*f+1].num+=xds[f].lan;
 45     xds[2*f].lan+=xds[f].lan;  xds[2*f+1].lan+=xds[f].lan;
 46     xds[f].lan=0;
 47 }
 48 void build(int f,int l,int r)
 49 {
 50     xds[f].zuo=l;  xds[f].you=r;
 51     if(l==r)  {xds[f].num=l;  xds[f].pos=l;  return ;}
 52     int mid=(l+r)>>1;
 53     build(2*f,l,mid);  build(2*f+1,mid+1,r);
 54     up(f);
 55 }
 56 void add(int f,int l,int r)
 57 {
 58     if(xds[f].zuo>=l&&xds[f].you<=r)  {xds[f].num++;  xds[f].lan++;  return ;}
 59     down(f);
 60     int mid=(xds[f].zuo+xds[f].you)>>1;
 61     if(l<=mid)  add(2*f,l,r);
 62     if(r>mid)  add(2*f+1,l,r);
 63     up(f);
 64 }
 65 int Q(int f,int l,int r,int w)
 66 {
 67     if(xds[f].num<w)  return -1;
 68     if(xds[f].zuo>=l&&xds[f].you<=r)  return xds[f].pos;
 69     down(f);
 70     int mid=(xds[f].zuo+xds[f].you)>>1,as=-5;
 71     if(l<=mid)  as=max(as,Q(2*f,l,r,w));
 72     if(r>mid)  as=max(as,Q(2*f+1,l,r,w));
 73     return as;
 74 }
 75 int main()
 76 {
 77 //    freopen("sequence0.in","r",stdin);
 78 //    freopen("3.out","w",stdout);
 79     n=read();
 80     for(int i=1;i<=n;++i)  {a[i]=read();  pos[a[i]]=i;}
 81     m=read();
 82     for(int i=1;i<=m;++i)
 83     {
 84         q[i].l=read();  q[i].r=read();  q[i].id=i;
 85         qua[q[i].r].push_back(q[i]);
 86     }
 87     build(1,1,n);
 88     for(int i=1;i<=n;++i)
 89     {
 90         for(int j=0;j<qua[i].size();++j)  quary.push(qua[i][j]);
 91         if(a[i]-1>=1&&pos[a[i]-1]<i)  add(1,1,pos[a[i]-1]);
 92         if(a[i]+1<=n&&pos[a[i]+1]<i)  add(1,1,pos[a[i]+1]);  
 93         while(quary.size())
 94         {
 95             node ls=quary.top();
 96             ans=Q(1,1,ls.l,i);
 97             if(ans==-1)  break;
 98             else  {ansl[ls.id]=ans;  ansr[ls.id]=i;  quary.pop();}
 99         }
100     }
101     for(int i=1;i<=m;++i)  printf("%d %d\n",ansl[i],ansr[i]);
102     return 0;
103 }
View Code

 

posted @ 2019-08-08 20:37  hzoi_X&R  阅读(144)  评论(0编辑  收藏  举报