对Y分块,对于Y<K,每一次1操作暴力修改这个Y的最大值,时间复杂度o(K);对于Y>K,维护一颗权值线段树并查询大于iK且离iK最近的数,时间复杂度o(6000000/K)(还有一个log),大约取K=2000左右(可以不用权值线段树而用并查集维护,复杂度较低)

[bzoj4320]Homework_时间复杂度[bzoj4320]Homework_权值线段树_02
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define K 3000
 4 #define L (k<<1)
 5 #define R (L+1)
 6 #define mid (l+r>>1)
 7 #define ma 300000
 8 int n,x,ans[ma],f[ma<<2];
 9 char s[11];
10 void update(int k,int l,int r,int x){
11     if (l==r){
12         f[k]=l;
13         return;
14     }
15     if (x<=mid)update(L,l,mid,x);
16     else update(R,mid+1,r,x);
17     f[k]=min(f[L],f[R]);
18 }
19 int query(int k,int l,int r,int x,int y){
20     if ((l>y)||(x>r))return 0x3f3f3f3f;
21     if ((x<=l)&&(r<=y))return f[k];
22     return min(query(L,l,mid,x,y),query(R,mid+1,r,x,y));
23 }
24 int main(){
25     scanf("%d",&n);
26     memset(f,0x3f,sizeof(f));
27     memset(ans,0x3f,sizeof(ans));
28     for(int i=1;i<=n;i++){
29         scanf("%s%d",s,&x);
30         if (s[0]=='A'){
31             for(int j=1;j<=K;j++)ans[j]=min(ans[j],x%j);
32             update(1,1,ma,x);
33             continue;
34         }
35         if (x<=K){
36             printf("%d\n",ans[x]);
37             continue;
38         }
39         ans[0]=x;
40         for(int j=0;j*x<=ma;j++)ans[0]=min(ans[0],query(1,1,ma,j*x,ma)-j*x);
41         printf("%d\n",ans[0]);
42     }
43 }
View Code