优美序列(线段树 分块 ST算法)

如此显然的线段树,我又瞎了眼了

事实上跟以前的奇袭很像.......

只要满足公式maxn-minn(权值)==r-l即可

所以可以考虑建两颗树,一棵节点维护位置,一棵权值,

每次从一棵树树上查询信息,如果满足公式就停止,不然两颗树不断扩展区间

当然也可以用ST啦(查询O(1)优于线段树)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<string>
 6 #include<set>
 7 #include<map>
 8 #include<vector>
 9 #include<cmath>
10 #define int long long
11 #define MAXN 100101
12 using namespace std;
13 char buffer[1<<20|1],*S,*T;
14 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,1<<20|1,stdin),S==T))?EOF:*S++)
15 int read()
16 {
17     int x=0;char c=getchar();
18     while(c<'0'||c>'9')c=getchar();
19     while(c>='0'&&c<='9')
20     {
21           x=(x<<1)+(x<<3)+(c^48);
22           c=getchar();
23     }
24     return x;
25 }
26 int a[MAXN];
27 int maxn,minn;
28 int n,m;int binn[MAXN];
29 int f[21][MAXN];int f_min[21][MAXN];//区间极值的最小位置,最大位置
30 int wei[21][MAXN];int wei_min[21][MAXN];
31 void work()
32 { 
33     int t=log(n)/log(2);
34     for(int j=1;j<=t;++j)
35     {
36         for(int i=1;i<=(n+1-binn[j]);++i)
37         {
38             f[j][i]=max(f[j-1][i],f[j-1][i+binn[j-1]]);
39             f_min[j][i]=min(f_min[j-1][i],f_min[j-1][i+binn[j-1]]);
40             wei[j][i]=max(wei[j-1][i],wei[j-1][i+binn[j-1]]);
41             wei_min[j][i]=min(wei_min[j-1][i],wei_min[j-1][i+binn[j-1]]);
42         }
43     }
44 } 
45 int maxn_wei,minn_wei;
46 void RMB(int l,int r)
47 {
48     int t=log(r-l+1)/log(2);
49     maxn_wei=max(f[t][l],f[t][r+1-binn[t]]);
50     minn_wei=min(f_min[t][l],f_min[t][r+1-binn[t]]);
51     return ;
52 }
53 
54 void RMB_wei(int l,int r)
55 {
56     int t=log(r-l+1)/log(2);
57     maxn=max(wei[t][l],wei[t][r+1-binn[t]]);
58     minn=min(wei_min[t][l],wei_min[t][r+1-binn[t]]);
59     return ;
60 }
61 signed main()
62 {
63      n=read();
64      for(int i=1;i<=n;++i)
65      {
66          a[i]=read();
67          f[0][a[i]]=i;f_min[0][a[i]]=i;
68          wei[0][i]=a[i];wei_min[0][i]=a[i];
69      }
70      binn[0]=1;
71      for(int i=1;i<=20;++i)binn[i]=(binn[i-1]<<1);
72      work();
73      m=read();
74      for(int i=1;i<=m;++i)
75      {
76          int l,r;
77          l=read();r=read();
78          maxn=0;minn=0x7ffffffff;maxn_wei=r;minn_wei=l;
79          while(maxn-minn!=maxn_wei-minn_wei)
80          {
81               RMB_wei(minn_wei,maxn_wei);
82               RMB(minn,maxn);
83          }
84          printf("%lld %lld\n",minn_wei,maxn_wei);
85      }
86 }
80 超时

100分:

%%%%%skyh 分块思想碾爆tarjan正解

因为每次区间不断扩展可能会扩展好多边,

那么我们把区间分块,这样预处理出块与块的答案

在实际查询中如果发现当前查询区间大于块的区间,那就可以判断是否用块跳跃

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<string>
  6 #include<set>
  7 #include<map>
  8 #include<vector>
  9 #include<cmath>
 10 #define int long long
 11 #define MAXN 100101
 12 using namespace std;
 13 int kuan[MAXN];int belong[MAXN];
 14 char buffer[1<<20|1],*S,*T;
 15 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,1<<20|1,stdin),S==T))?EOF:*S++)
 16 inline void read(int &x){x=0;
 17     register char c=getchar();
 18     while(c<'0'||c>'9')c=getchar();
 19     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=getchar();
 20 }
 21 int a[MAXN];
 22 int maxn,minn;int maxn_wei,minn_wei;
 23 int n,m;int binn[MAXN];
 24 int f[21][MAXN];int f_min[21][MAXN];//区间极值的最小位置,最大位置
 25 int wei[21][MAXN];int wei_min[21][MAXN];
 26 int ans_l[1000][1000];
 27 int ans_r[1000][1000];
 28 int tt,base;int Log[MAXN];
 29 void RMB(int l,int r)//通过权值查位置
 30 {
 31     int t=Log[r-l+1];
 32     maxn_wei=max(f[t][l],f[t][r+1-binn[t]]);
 33     minn_wei=min(f_min[t][l],f_min[t][r+1-binn[t]]);
 34     return ;
 35 }
 36 void RMB_wei(int l,int r)//通过位置察权值
 37 {
 38     int t=Log[r-l+1];
 39     maxn=max(wei[t][l],wei[t][r+1-binn[t]]);
 40     minn=min(wei_min[t][l],wei_min[t][r+1-binn[t]]);
 41     return ;
 42 }
 43 void work()
 44 { 
 45     int t=Log[n];
 46     for(int j=1;j<=t;++j)
 47     {
 48         for(int i=1;i<=(n+1-binn[j]);++i)
 49         {
 50             f[j][i]=max(f[j-1][i],f[j-1][i+binn[j-1]]);
 51             f_min[j][i]=min(f_min[j-1][i],f_min[j-1][i+binn[j-1]]);
 52             wei[j][i]=max(wei[j-1][i],wei[j-1][i+binn[j-1]]);
 53             wei_min[j][i]=min(wei_min[j-1][i],wei_min[j-1][i+binn[j-1]]);
 54         }
 55     }
 56     for(int i=1;i<base;++i)
 57     {
 58         for(int j=i+1;j<=base;++j)
 59         {
 60             int l=kuan[i],r=kuan[j];//位置查权值
 61             maxn=0;minn=0x7ffffffff;maxn_wei=r;minn_wei=l;
 62             while(maxn-minn!=maxn_wei-minn_wei)
 63             {
 64                  RMB_wei(minn_wei,maxn_wei);
 65                  RMB(minn,maxn);
 66             }   
 67             ans_l[i][j]=minn_wei;ans_r[i][j]=maxn_wei;
 68            // printf("ansl[%lld][%lld] i=%lld j=%lld\n",minn_wei,maxn_wei,i,j);
 69         }
 70     }
 71 } 
 72 
 73 signed main()
 74 {
 75      read(n);
 76      tt=pow(n,0.66666);
 77      Log[0]=-1;for(register int i=1;i<=n;++i) Log[i]=Log[i>>1]+1;
 78      for(int i=1;i;++i)
 79      {
 80         if(i*tt>=n)
 81         {
 82            kuan[i]=n;
 83            base=i;
 84            break;
 85         }
 86         else
 87            kuan[i]=i*tt;
 88      }
 89      for(int i=1;i<=n;++i)
 90      {
 91          read(a[i]);
 92          f[0][a[i]]=i;f_min[0][a[i]]=i;
 93          wei[0][i]=a[i];wei_min[0][i]=a[i];
 94          belong[i]=((i-1)/tt)+1;
 95      }
 96      binn[0]=1;
 97      for(int i=1;i<=20;++i)binn[i]=(binn[i-1]<<1);
 98      work();
 99      read(m);
100      for(int i=1;i<=m;++i)
101      {
102          int l,r;
103          read(l);read(r);
104          maxn=0;minn=0x7ffffffff;
105          maxn_wei=r;minn_wei=l; 
106          RMB_wei(minn_wei,maxn_wei);
107          while(maxn-minn!=maxn_wei-minn_wei)
108          {
109               //printf("maxn=%lld minn=%lld maxn_wei=%lld minwei=%lld\n",maxn,minn,maxn_wei,minn_wei);
110               RMB(minn,maxn);
111               int one=belong[minn_wei],two=belong[maxn_wei];
112               //printf("one=%lld two=%lld\n",one,two);
113               if(two>one+1&&one-1!=0)
114               {
115                     if(ans_l[one][two-1]<=minn_wei&&ans_r[one][two-1]>=maxn_wei)
116                     {
117                          minn_wei=ans_l[one][two-1];
118                          maxn_wei=ans_r[one][two-1];
119                          //printf("min_wei=%lld ma_wei=%lld\n",minn_wei,maxn_wei);
120                     }
121               }
122               //printf("maxn=%lld minn=%lld maxn_wei=%lld minwei=%lld\n",maxn,minn,maxn_wei,minn_wei);
123               RMB_wei(minn_wei,maxn_wei);
124               if(maxn-minn==maxn_wei-minn_wei)break;
125          }
126          printf("%lld %lld\n",minn_wei,maxn_wei);
127      }
128 }
%%%天皇

猜你喜欢

转载自www.cnblogs.com/Wwb123/p/11312029.html