#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<map> #define PII pair<int,int> #define int long long usingnamespace std; constint N = 1111500, MOD = 1e6, P = 131; intread(){char c=getchar();int s=0,f=1;for(;!isdigit(c);c=getchar())if(c=='-')f=-1;for(;isdigit(c);c=getchar())s=s*10+c-48;return s*f;} int n, tr[N], x[N], v[N], num[N], id[N]; //tr数组是树状数组 //x[i]表示排名为 i 的车离超过起点的距离 //v[i]表示排名为 i 的车的速度 //num[i]表示编号为 i 的车的排名 //id[i]表示排名为 i 的车的编号 structnode {//堆中的三元组 int x, y; double t; booloperator <(const node &b)const { return t > b.t || (t == b.t && num[x] > num[b.x]); }//重载运算符,让堆变成小根堆(按照时间和排名排序) };
priority_queue<node> q;
//接下来两个树状数组操作 voidadd(int x) {//添加 for (; x <= 100; x += x & -x)tr[x]++; } intask(int x) {//查询 int ans = 0; for (; x; x -= x & -x)ans = (ans + tr[x]) % MOD;//记得取模 return ans; }
signedmain() { n = read(); int ans = 0; //ans用来记超车次数 for (int i = 1; i <= n; i++) { x[i] = read(), v[i] = read(); num[i] = id[i] = i; //初始化 ans = (ans + ask(100) - ask(v[i])) % MOD; add(v[i]); //树状数组操作 if (i ^ 1 && v[i - 1] > v[i]) //如果 i!=1 并且排名比他小一的车速度比他快 q.push((node) { i - 1, //前一辆车 i, //后一辆车 (double)(x[i] - x[i - 1]) / (v[i - 1] - v[i]) //超车时间 });//入堆 } printf("%lld \n", ans); //输出超车次数 int t = 1; //t用来记录个数,保证输出不超过10000个 while (t <= 10000 && q.size()) { int X = q.top().x, Y = q.top().y; q.pop(); //X是前一辆车的编号,Y是后一辆车的编号 if (num[X] + 1 != num[Y])continue; //如果两辆车的排名不相邻(不是最先发生超车)则跳过。 printf("%lld %lld\n", X, Y); //输出 t++; swap(id[num[X]], id[num[Y]]); swap(v[num[X]], v[num[Y]]); swap(x[num[X]], x[num[Y]]); swap(num[X], num[Y]); //交换 X 车与 Y 车的位置 //交换后 X 车在前,Y 车在后(原本 Y 前 X 后) if (num[X] < n && v[num[X]] > v[num[X] + 1] && num[id[num[X]]] + 1 == num[id[num[X] + 1]]) //如果交换后 X 的排名不是 n (X 前还有车) //并且 X 车速大于 X 前面那辆 //并且两辆车的排名相邻 //最后一句可能有点绕,多读几遍,手动模拟一下就好了 q.push((node) { id[num[X]], //前一辆车编号 id[num[X] + 1], //后一辆车编号 (double)(x[num[X] + 1] - x[num[X]]) / (v[num[X]] - v[num[X] + 1]) //时间 });