关于读入速度在不同题目中的差异(?)

学术版

Shunpower @ 2022-05-17 17:16:05

在 这个帖子 中,除我以外的很多 OIer 都表示关同步流比 scanf/printf 快。

比如里面提到的这个例子:

  • 使用C++风格IO
  • 使用C风格IO
  • 未关同步和绑定

这道题读入了 3\cdot10^6 个数。

但是在 P8251 [NOI Online 2022 提高组] 丹钓战 这个题,您可以检索我的提交记录,这里放了其中五份:

  • https://www.luogu.com.cn/record/72828316
  • https://www.luogu.com.cn/record/72828360
  • https://www.luogu.com.cn/record/72828391
  • https://www.luogu.com.cn/record/72829399
  • https://www.luogu.com.cn/record/75919105

这五份都是一模一样的使用关闭同步流读入的考试代码,前四份是我考完之后交的,第五份是我刚才交的。可以观察到最是有许多点 TLE。

但是当我们换为 scanf/printf 读入的时候,这份代码跑得快了很多:

  • https://www.luogu.com.cn/record/75919138
  • https://www.luogu.com.cn/record/72828206
  • https://www.luogu.com.cn/record/72612176
  • https://www.luogu.com.cn/record/72611610

第一份是我刚才交的,其他的都是我考后交的。都是一模一样的只是将前面那份代码的读入方式修改的代码,可以观察到完全是可以 AC 的而且与评测机波动 无关。

这道题的读入量最大为 2\cdot 10^6 个数。

这道题有 O2 优化,因此我的问题:

1.O2 是否影响读入方式的相对快慢,若影响,是否可以给出不同评测方式在 O2 下的速度排名?

2.是否可以给出“这么多的读入量适用的读入方式”的表?

3.解决这道题为什么 scanf/printf 快的问题。

相关内容:我的另一个帖子 关于 CCF 和你谷评测机差异和吸氧

代码二楼。


by Shunpower @ 2022-05-17 17:16:30

//Why Card My Simple Number?!!!!
//233
//I'm No-rain......
//555 
//If I can't get my AC,I will cry.
//Thanks for your help,CCF!
#include <bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define fr1(i,x,y) for(int (i)=(x);i<=(y);(i)++)
#define fr2(i,x,y) for(int (i)=(x);i>=(y);(i)--)
#define mp(x,y) make_pair((x),(y))
#define debug puts("Chery AKs IOI")
using namespace std;
const int N=5e5+10;
int tnt;
struct node{
    int a,b,id;
};
int n,q;
pii a[N];
//int maxb,nowm;
//map <int,int> ap;
int pre[N];
stack <node> s;
struct Segment_Tree{
    int ls,rs,sum;
} k[N*80];
int rot[N];
int l,r;
inline void insert(int &p,int lastp,int l,int r,int idx){
    if(!p){
        tnt++;
        p=tnt;
    }
    k[p].sum=k[lastp].sum;
    k[p].sum++;
    if(l==r){
        return;
    }
    int m=(l+r)>>1;
    if(idx<=m){
        insert(k[p].ls,k[lastp].ls,l,m,idx);
        k[p].rs=k[lastp].rs;
    }
    else{
        insert(k[p].rs,k[lastp].rs,m+1,r,idx);
        k[p].ls=k[lastp].ls;
    }
//  k[p].sum=k[k[p].ls].sum+k[k[p].rs].sum;
}
//void deb(int p,int l,int r){
////    cout<<p<<","<<l<<","<<r<<","<<k[p].sum<<endl;
//  if(l==r){
//      return;
//  }
//  int m=(l+r)>>1;
//  deb(k[p].ls,l,m);
//  deb(k[p].rs,m+1,r);
//}
inline int query(int p,int l,int r,int ml,int mr){
    if(ml<=l&&r<=mr){
        int x=k[p].sum;
//      cout<<"hjl:"<<p<<","<<l<<","<<r<<","<<k[p].sum<<endl;
        return k[p].sum;
    }
    int m=(l+r)>>1;
    int ans=0;
    if(ml<=m){
        ans+=query(k[p].ls,l,m,ml,mr);
    }
    if(m<mr){
        ans+=query(k[p].rs,m+1,r,ml,mr);
    }
    return ans;
}
int main(){
//  freopen("stack.in","r",stdin);
//  freopen("stack.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n>>q;
    fr1(i,1,n){
        cin>>a[i].fi;
    }
    fr1(i,1,n){
        cin>>a[i].se;
    }
//  ap[a[1].fi]=1;
//  maxb=a[1].se;
    s.push({a[1].fi,a[1].se,1});
//  nowm=1;
    fr1(i,2,n){
        while(!s.empty()){
            if(s.top().a==a[i].fi||s.top().b<=a[i].se){
                s.pop();
            }
            else{
                break;
            }
        }
        int x=s.empty()?0:s.top().id;
        s.push({a[i].fi,a[i].se,i});
        pre[i]=x;
    }
    fr1(i,1,n){
        insert(rot[i],rot[i-1],0,n,pre[i]);
//      cout<<"1111"<<endl;
//      deb(rot[i],0,n);
    }
//  deb(rot[n],0,n);
//  fr1(i,1,n){
//      cout<<rot[i]<<" ";
//  }
//  puts("");
    fr1(i,1,q){
        cin>>l>>r;
        cout<<query(rot[r],0,n,0,l-1)-query(rot[l-1],0,n,0,l-1)<<endl;
    }
    return 0;
}
//Everything For Ji
//Everything For Lin
//Everything For You
//Teens-in-Times HJL
//20040615 Forever. 

by WYXkk @ 2022-05-17 17:22:20

@Zealous_YH 你的关同步相对于我知道的版本少写了两句 cin.tie(NULL);cout.tie(NULL);,可能是这个的问题吧?


by Shunpower @ 2022-05-17 17:25:59

@WYXkk

emm,那我再测测


by Dr_Gilbert @ 2022-05-17 17:26:48

@Zealous_YH
您好,使用endl将自动刷新缓冲区,如果频繁刷新缓冲区也会导致速度变慢,建议换成 \n 。同时请关闭绑定,效率更高。这是用我小号提交的,添加我所说几项的您的代码,可以看到是通过的。记录
添加的代码:

#define endl '\n'
...
cin.tie(nullptr)
cout.tie(nullptr)

by Shunpower @ 2022-05-17 17:28:05

@WYXkk

似乎还是不太行,80 pts


by Shunpower @ 2022-05-17 17:29:24

@Dr_Gilbert

thx,所以 endl 在关同步的情况下是不会被加速的吗?还是说优化非常少?


by Shunpower @ 2022-05-17 17:32:45

@Zealous_YH

在仅仅使用

cin.tie(nullptr)
cout.tie(nullptr)

的情况下,也只能获得 85 分的好成绩。

但是在不使用 endl 的情况下,确实可以 AC

所以希望可以解决一下关于 endl 的效率问题。

所以 endl 在关同步的情况下是不会被加速的吗?还是说优化非常少?


by Dr_Gilbert @ 2022-05-17 17:32:55

@Zealous_YH 关不关同步和刷新缓冲区是两回事


by Shunpower @ 2022-05-17 17:34:57

@Dr_Gilbert

emm,因此 endl 与同步流无关对吧

ok,谢谢您!


by Shunpower @ 2022-05-17 17:35:32

好的 我明白了 此贴终,谢谢大家

这个题上的所有问题算是结束了


|