2015百度之星1002 查找有序序列(RMQ+主席树模板水过)
题意:求在数列中能找到几个个长度为k 的区间,里面的 k 个数字排完序后是连续的。
思路:枚举范围,判断区间内是否有重复的数字(主席树),没有的话求区间最大-区间最小(RMQ),判断是否等于K,是的话sum++,否则continue;
主席树:原理不太懂,暂时还没能到能研究的水平,不过知道时间复杂度之类的,以后希望能用到的时候不是敲完上交了才知道超时了。。。。
时间复杂度
建树 O(n);
更新 O(log(n));
查询 O(log(n));
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <map> 6 using namespace std; 7 #define MAXN 50010 8 #define Max(x,y) (x>y?x:y) 9 #define Min(x,y) (x>y?y:x) 10 int maxsum[MAXN][20],minsum[MAXN][20];//表示从第i个数起连续2^j个数中的最大值/最小值 11 int num; 12 void RMQ() 13 { 14 for(int j=1; j<20; j++) 15 for(int i=1; i<=num; i++) 16 { 17 if(i+(1<<j)-1 <= num) 18 { 19 maxsum[i][j]=Max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]); 20 minsum[i][j]=Min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]); 21 } 22 } 23 } 24 /* 25 区间内是否有重复数字第几大的数字 26 */ 27 const int M = MAXN * 100; 28 int a[MAXN]; 29 int T[MAXN],lson[M],rson[M],c[M]; 30 int tot; 31 int build(int l,int r) 32 { 33 int root = tot++; 34 c[root] = 0; 35 if(l != r) 36 { 37 int mid = (l+r)>>1; 38 lson[root] = build(l,mid); 39 rson[root] = build(mid+1,r); 40 } 41 return root; 42 } 43 int update(int root,int pos,int val) 44 { 45 int newroot = tot++, tmp = newroot; 46 c[newroot] = c[root] + val; 47 int l = 1, r = num; 48 while(l < r) 49 { 50 int mid = (l+r)>>1; 51 if(pos <= mid) 52 { 53 lson[newroot] = tot++; 54 rson[newroot] = rson[root]; 55 newroot = lson[newroot]; 56 root = lson[root]; 57 r = mid; 58 } 59 else 60 { 61 rson[newroot] = tot++; 62 lson[newroot] = lson[root]; 63 newroot = rson[newroot]; 64 root = rson[root]; 65 l = mid+1; 66 } 67 c[newroot] = c[root] + val; 68 } 69 return tmp; 70 } 71 int query(int root,int pos) 72 { 73 int ret = 0; 74 int l = 1, r = num; 75 while(pos < r) 76 { 77 int mid = (l+r)>>1; 78 if(pos <= mid) 79 { 80 r = mid; 81 root = lson[root]; 82 } 83 else 84 { 85 ret += c[lson[root]]; 86 root = rson[root]; 87 l = mid+1; 88 } 89 } 90 return ret + c[root]; 91 } 92 int main() 93 { 94 int i,j,t,Query,kase = 1; 95 while(scanf("%d%d",&num,&Query) != EOF) 96 { 97 for(i=1; i<=num; i++) 98 { 99 scanf("%d",&maxsum[i][0]); 100 a[i] = maxsum[i][0]; 101 minsum[i][0]=maxsum[i][0]; 102 } 103 RMQ(); 104 T[num+1] = build(1,num); 105 map<int,int>mp; 106 for(int i = num; i>= 1; i--) 107 { 108 if(mp.find(a[i]) == mp.end()) 109 { 110 T[i] = update(T[i+1],i,1); 111 } 112 else 113 { 114 int tmp = update(T[i+1],mp[a[i]],-1); 115 T[i] = update(tmp,i,1); 116 } 117 mp[a[i]] = i; 118 } 119 int w,maxl,minl; 120 printf("Case #%d:\n",kase++); 121 while(Query--) 122 { 123 scanf("%d",&w); 124 int number = 0; 125 for(int i = 1; i<=num; i++) 126 { 127 int st = i,en = w+i-1; 128 int NUM = query(T[st],en); 129 if(NUM == w) 130 { 131 int k=(int)((log(en-st+1))/log(2.0)); 132 maxl=Max(maxsum[st][k],maxsum[en-(1<<k)+1][k]); 133 minl=Min(minsum[st][k],minsum[en-(1<<k)+1][k]); 134 if(maxl - minl == w-1) 135 number++; 136 } 137 } 138 printf("%d\n",number); 139 } 140 } 141 return 0; 142 }
人生就像心电图,想要一帆风顺,除非game-over