czyarl:https://www.cnblogs.com/czyarl/p/14515009.html
题目大意:有一个长度为n的序列,初始全为0。有两种操作:第一种是区间赋值,并且值全为正数且单调增;第二种是询问一个位置的值是什么。
所有的操作都是由程序在运行中根据seed随机生成的。也就是说,你可以无视入读带来的常数影响。
n的长度:6250000
操作1的次数:20000000
操作2的次数:10000
时间限制:8s
空间:1024Mb
思考:这道题的前身是某道题中的分块部分,但它只需要支持前后缀修改,单点查询。在czyarl冷静思考过后,想到了这个能支持O(1)区间修改,O(sqrt(n))单点查询(但常数很大,被zkw几近乱杀且用途很狭窄)的分块做法。(不过好像还没有见到任何一道题用过这个技巧)
我们先考虑这样一种分块,它建立在长度为n的序列上,支持O(1)区间修改,O(n)单点询问。首先,我们将其分为根号个块,并且对每个块开一个大小为$size_i*size_i$的二维数组tag[][]用来记录修改的信息,其中size是这一个块的大小。其次,我们继续开一个大小为$\sqrt{n}*\sqrt{n}$的二维数组tagB[][],用来保存对于整块修改的信息。
对于一次修改操作,如果修改的区间完全落入一个块内,那么就在对应的tag[l][r]上进行一次更新。如果它跨过了若干区间,我们先在对应的左右块的tag[][]上进行一次更新,接着在tagB[cl][cr]上进行更新,其中cl、cr分别为l所属块的编号+1、r所属块的编号-1。
对于一次询问操作,我们先定位到所属的块,接着花$size_i*size_i$的时间询问这个块内tag[][]的答案。还有一些对整块进行修改的操作,花$\sqrt{n}*\sqrt{n}$的时间询问tagB[][]的答案。这样,我们就做到了O(1)区间修改和O(n)单点查询。这个数据结构的空间是O(n^1.5)的。
回到原问题上,我们先对原始的序列进行分块,并对每一个块使用一个上述的数据结构。如果一次修改完全落入一个块呢,那我们直接对这个块进行上述的修改操作。如果这次修改跨过若干个块,注意到跨过的整块的个数只有$\sqrt{n}$个,因此我们再对原数组使用一个上述的数据结构,用来记录修改整块的信息。
对于一次询问,我们先定位到所属的块,得到这个块内的答案。接着,我们再询问整块的答案,就得到了想要的东西。
于是,就做到了O(1)修改和O(sqrt(n))询问,空间复杂度是O(n^1.25)的(因为用了根号个上述的数据结构,每个数据结构的长度是n^0.5,n^0.75*n^0.5=n^1.25)。
优化:我们发现一次修改最坏要改9次数组,而其中有两次实际上只有前后缀修改。对于前后缀修改,我们只要在相应位置记录下答案,在询问时去找就行了。
czy代码:
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define MAXN 2560100 4 #define MAXSQR1 2560100 5 #define MAXSQR2 1610 6 #define MAXSQR4 41 7 #define INF 1010000000 8 using namespace std; 9 template<typename T> void Read(T &cn) 10 { 11 char c; int sig = 1; 12 while(!isdigit(c = getchar())) if(c == '-') sig = 0; 13 if(sig) {cn = c-48; while(isdigit(c = getchar())) cn = cn*10-48+c; } 14 else {cn = 48-c; while(isdigit(c = getchar())) cn = cn*10+48-c; } 15 } 16 template<typename T> void Write(T cn) 17 { 18 T cm = 0; int cx = cn%10, wei = 0; cn = cn/10; 19 if(cn < 0 || cx < 0) {putchar('-'); cn = -cn; cx = -cx; } 20 while(cn) wei++, cm = cm*10+cn%10, cn = cn/10; 21 while(wei--) putchar(cm%10+48), cm = cm/10; 22 putchar(cx+48); 23 } 24 template<typename T> void WriteS(T cn) {Write(cn); putchar(' '); } 25 template<typename T> void WriteL(T cn) {Write(cn); puts(""); } 26 namespace getNum{ 27 unsigned lst; 28 int q1, q2, A, n; 29 void pre(int cn, int cq1, int cq2, int seed, int cA) {q1 = cq1, q2 = cq2, lst = seed, A = cA, n = cn; } 30 unsigned get_r(unsigned cn) {lst ^= lst<<7; lst ^= lst>>3; lst ^= lst<<13; return lst%cn; } 31 int get_n(int l, int r) {return l + get_r(r-l+1); } 32 void get_val(int &val) {val = get_n(1, A); } 33 void get_ne(int &typ, int &pos, int &l, int &r, int &val) 34 { 35 typ = get_n(1, q1+q2)<=q1 ? 1 : 2; 36 if(typ == 1) q1--, l = get_n(1,n), r = get_n(l, n), val = get_n(1, A); 37 if(typ == 2) q2--, pos = get_n(1,n); 38 } 39 } 40 template<typename T> void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; } 41 template<typename T> void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; } 42 struct Blo4{ 43 int a[MAXSQR4+1][MAXSQR4+1]; 44 int n; 45 void build(int ca[], int l, int r) 46 { 47 n = r-l+1; 48 for(int i = 1;i<=n;i++) 49 { 50 a[i][i] = ca[l+i-1]; 51 for(int j = i+1;j<=n;j++) a[i][j] = min(a[i][j-1], ca[l+j-1]); 52 } 53 } 54 void qu_min(int l, int r, int cn) {Min(a[l][r], cn); } 55 int query(int cn) 56 { 57 int ans = a[cn][cn]; 58 for(int i = 1;i<=cn;i++) for(int j = cn;j<=n;j++) Min(ans, a[i][j]); 59 return ans; 60 } 61 }; 62 struct Blo2{ 63 Blo4 a[MAXSQR4+2]; 64 int pre[MAXSQR2+1], suf[MAXSQR2+1], blo[MAXSQR2+1], tou[MAXSQR2+1], wei[MAXSQR2+1]; 65 int tmp[MAXSQR4+1]; 66 int n, Sqr, alen; 67 int hav_pre, hav_suf; 68 void build(int ca[], int l, int r) 69 { 70 n = r-l+1; Sqr = sqrt(n); 71 for(int i = 1;i<=n;i++) pre[i] = suf[i] = INF; hav_pre = hav_suf = 0; 72 for(int i = 1;i<=n;) 73 { 74 int j = min(n, i+Sqr-1); alen++; 75 tou[alen] = i; wei[alen] = j; 76 for(int ij = i;ij<=j;ij++) blo[ij] = alen; 77 a[alen].build(ca, l+i-1, l+j-1); 78 tmp[alen] = INF; 79 i = j+1; 80 } 81 ++alen; a[alen].build(tmp, 1, alen-1); 82 } 83 void qu_min_suf(int l, int cn) {Min(suf[l], cn), hav_suf = 1; } 84 void qu_min_pre(int r, int cn) {Min(pre[r], cn), hav_pre = 1; } 85 void qu_min(int l, int r, int cn) 86 { 87 if(blo[l] == blo[r]) a[blo[l]].qu_min(l-tou[blo[l]]+1, r-tou[blo[l]]+1, cn); 88 else { 89 a[blo[l]].qu_min(l-tou[blo[l]]+1, wei[blo[l]]-tou[blo[l]]+1, cn); 90 a[alen].qu_min(blo[l]+1, blo[r]-1, cn); 91 a[blo[r]].qu_min(1, r-tou[blo[r]]+1, cn); 92 } 93 } 94 int query(int cn) 95 { 96 int ans = min(a[alen].query(blo[cn]), a[blo[cn]].query(cn-tou[blo[cn]]+1)); 97 if(hav_pre) for(int i = cn;i<=n;i++) Min(ans, pre[i]); 98 if(hav_suf) for(int i = 1;i<=cn;i++) Min(ans, suf[i]); 99 return ans; 100 } 101 }; 102 struct Blo1{ 103 Blo2 a[MAXSQR2+2]; 104 int blo[MAXSQR1+1], tou[MAXSQR1+1], wei[MAXSQR1+1]; 105 int tmp[MAXSQR2+1]; 106 int n, Sqr, alen; 107 void build(int ca[], int l, int r) 108 { 109 n = r-l+1; Sqr = sqrt(n); 110 for(int i = 1;i<=n;) 111 { 112 int j = min(n, i+Sqr-1); alen++; 113 tou[alen] = i; wei[alen] = j; 114 for(int ij = i;ij<=j;ij++) blo[ij] = alen; 115 a[alen].build(ca, l+i-1, l+j-1); 116 tmp[alen] = INF; 117 i = j+1; 118 } 119 ++alen; a[alen].build(tmp, 1, alen-1); 120 } 121 void qu_min(int l, int r, int cn) 122 { 123 if(blo[l] == blo[r]) a[blo[l]].qu_min(l-tou[blo[l]]+1, r-tou[blo[l]]+1, cn); 124 else { 125 a[blo[l]].qu_min_suf(l-tou[blo[l]]+1, cn); 126 if(blo[l] < blo[r]-1) a[alen].qu_min(blo[l]+1, blo[r]-1, cn); 127 a[blo[r]].qu_min_pre(r-tou[blo[r]]+1, cn); 128 } 129 } 130 int query(int cn) {return min(a[alen].query(blo[cn]), a[blo[cn]].query(cn-tou[blo[cn]]+1)); } 131 }; 132 Blo1 T; 133 int n, q1, q2, Seed, A; 134 int a[MAXN+1]; 135 int main() 136 { 137 cerr<<(sizeof(T))/1024.0/1024.0<<endl; 138 // freopen("block.in","r",stdin); 139 freopen("block.out","w",stdout); 140 Read(n); Read(q1); Read(q2); Read(A); Read(Seed); 141 getNum::pre(n, q1, q2, Seed, A); 142 for(int i = 1;i<=n;i++) getNum::get_val(a[i]); 143 T.build(a, 1, n); 144 LL ans = 0; 145 for(int i = 1;i<=q1+q2;i++) 146 { 147 int btyp, bx, bl, br, bpos; 148 getNum::get_ne(btyp, bpos, bl, br, bx); 149 if(btyp == 1) T.qu_min(bl, br, bx); 150 if(btyp == 2) ans = ans ^ (1ll*T.query(bpos)*i); 151 } 152 WriteL(ans); 153 return 0; 154 }
我的代码:(用了vector,修改甚至要改9次,因此慢了4倍)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3E6+5; 4 struct info 5 { 6 int x; 7 info(int a=0,int b=0):x(a){} 8 }; 9 inline void chmax(info&x,const info&y) 10 { 11 if(y.x>x.x) 12 x=y; 13 } 14 inline int get(int l,int r,int len) 15 { 16 return l*len+r-l*(l+1)/2; 17 } 18 struct BLOCK 19 { 20 int n,len,totC,bel[1605],size[1605],toL[1605],toR[1605]; 21 vector<info>tag[1605],tagB; 22 inline void build(int m) 23 { 24 n=m; 25 len=sqrt(n); 26 bel[0]=1; 27 ++size[1]; 28 for(int i=1;i<n;++i) 29 { 30 bel[i]=bel[i-1]+(i%len==0); 31 toR[bel[i]]=i; 32 ++size[bel[i]]; 33 } 34 for(int i=n-1;i>=0;--i) 35 toL[bel[i]]=i; 36 totC=bel[n-1]; 37 for(int i=1;i<=totC;++i) 38 tag[i].resize((size[i]+1)*size[i]/2); 39 tagB.resize((totC+1)*totC/2); 40 } 41 inline void change(int l,int r,const info&A) 42 { 43 int cl=bel[l],cr=bel[r]; 44 if(cl==cr) 45 { 46 chmax(tag[cl][get(l-toL[cl],r-toL[cl],size[cl])],A); 47 return; 48 } 49 chmax(tag[cl][get(l-toL[cl],size[cl]-1,size[cl])],A); 50 chmax(tag[cr][get(0,r-toL[cr],size[cr])],A); 51 if(cl+1<=cr-1) 52 chmax(tagB[get(cl+1,cr-1,totC)],A); 53 } 54 inline info ask(int pos) 55 { 56 info A(0,0); 57 int c=bel[pos],p=0; 58 int bias=pos-toL[c]; 59 for(int l=0;l<size[c];++l) 60 for(int r=l;r<size[c];++r,++p) 61 if(l<=bias&&bias<=r) 62 chmax(A,tag[c][p]); 63 p=0; 64 for(int l=0;l<totC;++l) 65 for(int r=l;r<totC;++r,++p) 66 if(l<=c&&c<=r) 67 chmax(A,tagB[p]); 68 return A; 69 } 70 }T1[1605],T2; 71 int n,len,totC,bel[maxn],toL[maxn],toR[maxn]; 72 inline int ask(int pos) 73 { 74 info A=T1[bel[pos]].ask(pos-toL[bel[pos]]); 75 chmax(A,T2.ask(bel[pos]-1)); 76 return A.x; 77 } 78 int TI; 79 inline void change(int l,int r,int x) 80 { 81 info A(x,++TI); 82 int cl=bel[l],cr=bel[r]; 83 if(cl==cr) 84 T1[cl].change(l-toL[cl],r-toL[cl],A); 85 else 86 { 87 T1[cl].change(l-toL[cl],toR[cl]-toL[cl],A); 88 T1[cr].change(0,r-toL[cr],A); 89 if(cl<=cr-2) 90 T2.change(cl,cr-2,A); 91 } 92 } 93 int size[maxn]; 94 inline void init() 95 { 96 len=sqrt(n); 97 for(int i=1;i<=n;++i) 98 { 99 bel[i]=bel[i-1]+((i-1)%len==0); 100 toR[bel[i]]=i; 101 ++size[bel[i]]; 102 } 103 for(int i=n;i>=1;--i) 104 toL[bel[i]]=i; 105 totC=bel[n]; 106 for(int i=1;i<=totC;++i) 107 T1[i].build(size[i]); 108 T2.build(totC); 109 } 110 mt19937 rd(233); 111 const int limit=5000; 112 inline int R(int l,int r) 113 { 114 return rd()%(r-l+1)+l; 115 } 116 int main() 117 { 118 freopen("a.out","w",stdout); 119 ios::sync_with_stdio(false); 120 cin>>n; 121 init(); 122 int T; 123 cin>>T; 124 for(int i=1;i<=T;++i) 125 { 126 int opt; 127 if(i%limit==0) 128 opt=1; 129 else 130 opt=0; 131 if(opt==1) 132 { 133 int x=R(1,n); 134 cout<<ask(x)<<'\n'; 135 } 136 else 137 { 138 int l=R(1,n),r=R(1,n),x=i; 139 if(l>r) 140 swap(l,r); 141 change(l,r,x); 142 } 143 } 144 return 0; 145 }
我的代码:优化了很多很多,但变得不可读了。在n=6250000,T=100000000时比zkw快两倍。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=7E6+5; 4 int n; 5 int tot2,tot3[2600],tot5; 6 int len2,len3[2600],len4,len5; 7 int bel2[maxn],bel3[maxn],bel5[maxn]; 8 int size2[2600],size3[500000],size5[2600]; 9 int toL2[2600],toR2[2600],toL3[500000],toR3[500000],toL5[2600],toR5[2600]; 10 int tag2[maxn],tag3[maxn*52],tag5[maxn],tag4[maxn]; 11 int bias2[2600],bias3[500000],bias5[500000]; 12 int pre2[maxn],suf2[maxn],pre4[maxn],suf4[maxn]; 13 inline int get(int l,int r,int len) 14 { 15 return l*len-l*(l+1)/2+r; 16 } 17 inline void init() 18 { 19 len2=sqrt(n); 20 for(int i=1;i<=n;++i) 21 { 22 bel2[i]=bel2[i-1]+((i-1)%len2==0); 23 ++size2[bel2[i]]; 24 toR2[bel2[i]]=i; 25 } 26 for(int i=n;i>=1;--i) 27 toL2[bel2[i]]=i; 28 tot2=bel2[n]; 29 for(int i=1;i<=tot2;++i) 30 { 31 len3[i]=sqrt(size2[i]); 32 for(int j=toL2[i];j<=toR2[i];++j) 33 { 34 bel3[j]=bel3[j-1]+((j-toL2[i])%len3[i]==0); 35 ++size3[bel3[j]]; 36 toR3[bel3[j]]=j; 37 } 38 for(int j=toR2[i];j>=toL2[i];--j) 39 toL3[bel3[j]]=j; 40 tot3[i]=bel3[toR2[i]]-bel3[toL2[i]]+1; 41 bias2[i]=bias2[i-1]+(tot3[i]+1)*tot3[i]/2; 42 } 43 for(int i=1;i<=bel3[n];++i) 44 bias3[i]=bias3[i-1]+(size3[i]+1)*size3[i]/2; 45 len4=tot2; 46 len5=sqrt(tot2); 47 for(int i=1;i<=tot2;++i) 48 { 49 bel5[i]=bel5[i-1]+((i-1)%len5==0); 50 ++size5[bel5[i]]; 51 toR5[bel5[i]]=i; 52 } 53 for(int i=tot2;i>=1;--i) 54 toL5[bel5[i]]=i; 55 tot5=bel5[tot2]; 56 for(int i=1;i<=tot5;++i) 57 bias5[i]=bias5[i-1]+(size5[i]+1)*size5[i]/2; 58 /* 59 for(int i=1;i<=n;++i) 60 cout<<bel2[i]<<" ";cout<<endl; 61 for(int i=1;i<=n;++i) 62 cout<<bel3[i]<<" ";cout<<endl; 63 for(int i=1;i<=tot2;++i) 64 cout<<bel5[i]<<" ";cout<<endl; 65 for(int i=1;i<=bel3[n];++i) 66 cout<<toL3[i]<<" ";cout<<endl;*/ 67 } 68 inline void chmax(int&x,int y) 69 { 70 x=max(x,y); 71 } 72 inline int ask(int pos) 73 { 74 int x=0; 75 int p=0; 76 int c3=bel3[pos]; 77 for(int l=toL3[c3];l<=toR3[c3];++l) 78 for(int r=l;r<=toR3[c3];++r,++p) 79 if(l<=pos&&pos<=r) 80 chmax(x,tag3[bias3[c3-1]+p]); 81 p=0; 82 int c2=bel2[pos]; 83 for(int l=bel3[toL2[c2]];l<=bel3[toR2[c2]];++l) 84 for(int r=l;r<=bel3[toR2[c2]];++r,++p) 85 if(l<=c3&&c3<=r) 86 chmax(x,tag2[bias2[c2-1]+p]); 87 for(int i=pos;bel2[i]==c2;--i) 88 chmax(x,suf2[i]); 89 for(int i=pos;bel2[i]==c2;++i) 90 chmax(x,pre2[i]); 91 p=0; 92 int c5=bel5[c2]; 93 for(int l=toL5[c5];l<=toR5[c5];++l) 94 for(int r=l;r<=toR5[c5];++r,++p) 95 if(l<=c2&&c2<=r) 96 chmax(x,tag5[bias5[c5-1]+p]); 97 p=0; 98 for(int l=1;l<=tot5;++l) 99 for(int r=l;r<=tot5;++r,++p) 100 if(l<=c5&&c5<=r) 101 chmax(x,tag4[p]); 102 for(int i=c2;bel5[i]==c5;--i) 103 chmax(x,suf4[i]); 104 for(int i=c2;bel5[i]==c5;++i) 105 chmax(x,pre4[i]); 106 return x; 107 } 108 inline void change(int l,int r,int x) 109 { 110 int cl2=bel2[l],cr2=bel2[r]; 111 if(cl2==cr2) 112 { 113 int cl3=bel3[l],cr3=bel3[r]; 114 if(cl3==cr3) 115 { 116 tag3[bias3[cl3-1]+get(l-toL3[cl3],r-toL3[cl3],size3[cl3])]=x; 117 } 118 else 119 { 120 tag3[bias3[cl3-1]+get(l-toL3[cl3],size3[cl3]-1,size3[cl3])]=x; 121 tag3[bias3[cr3-1]+get(0,r-toL3[cr3],size3[cr3])]=x; 122 if(cl3+1<=cr3-1) 123 { 124 tag2[bias2[cl2-1]+get(cl3+1-bel3[toL2[cl2]],cr3-1-bel3[toL2[cl2]],tot3[cl2])]=x; 125 } 126 } 127 } 128 else 129 { 130 int cl3=bel3[l],cr3=bel3[r]; 131 suf2[l]=x; 132 pre2[r]=x; 133 ++cl2,--cr2; 134 if(cl2>cr2) 135 return; 136 int cl5=bel5[cl2],cr5=bel5[cr2]; 137 if(cl5==cr5) 138 { 139 tag5[bias5[cl5-1]+get(cl2-toL5[cl5],cr2-toL5[cl5],size5[cl5])]=x; 140 } 141 else 142 { 143 suf4[cl2]=x; 144 pre4[cr2]=x; 145 if(cl5+1<=cr5-1) 146 { 147 tag4[get(cl5,cr5-2,bel5[tot2])]=x; 148 } 149 } 150 } 151 } 152 mt19937 rd(233); 153 const int limit=1000; 154 inline int R(int l,int r) 155 { 156 return rd()%(r-l+1)+l; 157 } 158 int main() 159 { 160 freopen("a.out","w",stdout); 161 ios::sync_with_stdio(false); 162 int T; 163 cin>>n; 164 init(); 165 cin>>T; 166 for(int i=1;i<=T;++i) 167 { 168 int opt; 169 if(i%limit==0) 170 opt=1; 171 else 172 opt=2; 173 if(opt==1) 174 { 175 int x=R(1,n); 176 cout<<ask(x)<<'\n'; 177 } 178 else 179 { 180 int l=R(1,n),r=R(1,n),x=i; 181 if(l>r) 182 swap(l,r); 183 change(l,r,x); 184 } 185 } 186 return 0; 187 }