玄学时间复杂度

P2801 教主的魔法

东郭 @ 2020-07-29 08:17:33

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
int n,m,num,a[1000001],b[1000001],bel[1000001],l[10001],r[10001],flag[10001];
inline void change(int x){
    for(int i=l[bel[x]];i<=r[bel[x]];i++)b[i]=a[i];
    sort(b+l[bel[x]],b+r[bel[x]]+1);
    return;
}
inline void update(int x,int y,int z){
    if(bel[x]==bel[y]){
        for(int i=x;i<=y;i++)a[i]+=z;
        change(x);
        return;
    }
    for(int i=x;i<=r[bel[x]];i++)a[i]+=z;
    for(int i=l[bel[y]];i<=y;i++)a[i]+=z;
    change(x);change(y);
    for(int i=bel[x]+1;i<=bel[y]-1;i++)flag[i]+=z;
    return;
}
inline int find(int x,int y,int z){
    while(x<=y){
        int mid=(x+y)>>1;
        if(b[mid]<z) x=mid+1;
        else y=mid-1;
    }
    return y;
}
inline int query(int x,int y,int z){
    int ans=0;
    if(bel[x]==bel[y]){
        for(int i=x;i<=y;i++)
            if(a[i]+flag[bel[x]]>=z)
                ans++;
        return ans;
    }
    for(int i=x;i<=r[bel[x]];i++)
        if(a[i]+flag[bel[x]]>=z)
                ans++;
    for(int i=l[bel[y]];i<=y;i++)
        if(a[i]+flag[bel[y]]>=z)
                ans++;
    for(int i=bel[x]+1;i<=bel[y]-1;i++)
        ans+=r[i]-find(l[i],r[i],z-flag[bel[i]])+1;
    return ans;
}
int main(){
    num=sqrt(n);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=num;i++) l[i]=r[i-1]+1,r[i]=i*num;
    if(r[num]<n) num++,l[num]=r[num-1]+1,r[num]=n;
    for(int i=1;i<=num;i++)
        for(int j=l[i];j<=r[i];j++)
            bel[j]=i,b[j]=a[j];
    for(int i=1;i<=num;i++)
        sort(b+l[i],b+r[i]+1);
    char lon[3];
    int x1,x2,x3;
    while(m--){
        cin>>lon;
        scanf("%d%d%d",&x1,&x2,&x3);
        if(lon[0]=='A') printf("%d\n",query(x1,x2,x3));
        else update(x1,x2,x3);
    }
return 0;
}

时间复杂度与题解一样,TLE了5,6,7,8,10五个点。


by 东郭 @ 2020-07-29 08:20:50

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
int n,m,num,a[1000001],b[1000001],bel[1000001],l[10001],r[10001],flag[10001];
inline void change(int x){
    for(int i=l[bel[x]];i<=r[bel[x]];i++)b[i]=a[i];
    sort(b+l[bel[x]],b+r[bel[x]]+1);
    return;
}
inline void update(int x,int y,int z){
    if(bel[x]==bel[y]){
        for(int i=x;i<=y;i++)a[i]+=z;
        change(x);
        return;
    }
    for(int i=x;i<=r[bel[x]];i++)a[i]+=z;
    for(int i=l[bel[y]];i<=y;i++)a[i]+=z;
    change(x);change(y);
    for(int i=bel[x]+1;i<=bel[y]-1;i++)flag[i]+=z;
    return;
}
inline int find(int x,int y,int z){
    while(x<=y){
        int mid=(x+y)>>1;
        if(b[mid]<z) x=mid+1;
        else y=mid-1;
    }
    return y;
}
inline int query(int x,int y,int z){
    int ans=0;
    if(bel[x]==bel[y]){
        for(int i=x;i<=y;i++)
            if(a[i]+flag[bel[x]]>=z)
                ans++;
        return ans;
    }
    for(int i=x;i<=r[bel[x]];i++)
        if(a[i]+flag[bel[x]]>=z)
                ans++;
    for(int i=l[bel[y]];i<=y;i++)
        if(a[i]+flag[bel[y]]>=z)
                ans++;
    for(int i=bel[x]+1;i<=bel[y]-1;i++)
        ans+=r[i]-find(l[i],r[i],z-flag[bel[i]])+1;
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    num=sqrt(n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=num;i++) l[i]=r[i-1]+1,r[i]=i*num;
    if(r[num]<n) num++,l[num]=r[num-1]+1,r[num]=n;
    for(int i=1;i<=num;i++)
        for(int j=l[i];j<=r[i];j++)
            bel[j]=i,b[j]=a[j];
    for(int i=1;i<=num;i++)
        sort(b+l[i],b+r[i]+1);
    char lon[3];
    int x1,x2,x3;
    while(m--){
        cin>>lon;
        scanf("%d%d%d",&x1,&x2,&x3);
        if(lon[0]=='A') printf("%d\n",query(x1,x2,x3));
        else update(x1,x2,x3);
    }
return 0;
}

WA九个点


by Lidozs55 @ 2020-07-29 08:24:10

宁先试试O2?

话说我也不太清楚


by 东郭 @ 2020-07-29 08:28:24

O2也没过。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
int n,m,num,a[1000001],b[1000001],bel[1000001],l[10001],r[10001],flag[10001];
inline void change(int x){
    for(int i=l[bel[x]];i<=r[bel[x]];i++)b[i]=a[i];
    sort(b+l[bel[x]],b+r[bel[x]]+1);
    return;
}
inline void update(int x,int y,int z){
    if(bel[x]==bel[y]){
        for(int i=x;i<=y;i++)a[i]+=z;
        change(x);
        return;
    }
    for(int i=x;i<=r[bel[x]];i++)a[i]+=z;
    for(int i=l[bel[y]];i<=y;i++)a[i]+=z;
    change(x);change(y);
    for(int i=bel[x]+1;i<=bel[y]-1;i++)flag[i]+=z;
    return;
}
inline int find(int x,int y,int z){
    while(x<y){
        int mid=(x+y)>>1;
        if(b[mid]<z) x=mid+1;
        else y=mid-1;
    }
    return y;
}
inline int query(int x,int y,int z){
    int ans=0;
    if(bel[x]==bel[y]){
        for(int i=x;i<=y;i++)
            if(a[i]+flag[bel[x]]>=z)
                ans++;
        return ans;
    }
    for(int i=x;i<=r[bel[x]];i++)
        if(a[i]+flag[bel[x]]>=z)
                ans++;
    for(int i=l[bel[y]];i<=y;i++)
        if(a[i]+flag[bel[y]]>=z)
                ans++;
    for(int i=bel[x]+1;i<=bel[y]-1;i++)
        ans+=r[i]-find(l[i],r[i],z-flag[i])+1;
    return ans;
}
int main(){
    memset(flag,0,sizeof flag);
    scanf("%d%d",&n,&m);
    num=sqrt(n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=num;i++) l[i]=r[i-1]+1,r[i]=i*(n/num);
    if(r[num]<n) num++,l[num]=r[num-1]+1,r[num]=n;
    for(int i=1;i<=num;i++)
        for(int j=l[i];j<=r[i];j++)
            bel[j]=i,b[j]=a[j];
    for(int i=1;i<=num;i++)
        sort(b+l[i],b+r[i]+1);
    char lon[3];
    int x1,x2,x3;
    while(m--){
        cin>>lon;
        scanf("%d%d%d",&x1,&x2,&x3);
        if(lon[0]=='A') printf("%d\n",query(x1,x2,x3));
        else update(x1,x2,x3);
    }
return 0;
}

by _蒟蒻—信含_ @ 2020-07-29 08:42:51

for太多?这for多的(逃


by 东郭 @ 2020-07-29 08:44:00

主要是二分的锅


by _蒟蒻—信含_ @ 2020-07-29 08:45:02

@东郭 rxz的二分只有两行for主要是递归


by _蒟蒻—信含_ @ 2020-07-29 08:46:05

这题看不太懂你看我菜的连勾勾都没


by Anonymous_U @ 2020-07-29 08:59:29

把二分里while(x<y),改成while(x<=y) 把ans+=r[i]-find(l[i],r[i],z-flag[i])+1; 改成ans+=r[i]-find(l[i],r[i],z-flag[i]);


by Anonymous_U @ 2020-07-29 08:59:59

亲测能过


by 东郭 @ 2020-07-29 09:12:21

谢谢巨佬


| 下一页