分析

我们对于一个节点 考虑,如果有一个点 两维都大于 ,那么这个节点肯定不可能作为结尾。因为考虑一下,如果排列先出现 ,那么这个两维都是单调不降的,所以不可能转移到 ,反之,如果先出现 ,它一定保持不住结尾,最后整个图构成了一个有向无环图,每一个节点可以等概率转移到后置节点。那么一个节点对于它后面节点贡献就为,令考虑前 个,当前节点为结尾的概率 。那么它的贡献的计算 。因为它的贡献要被后面的节点等概率转移,所以 。那么这个就是个二维偏序的问题,考虑树状数组优化。先求出 。然后由小到大枚举 就好了,最后还要乘以所有方案数。时间复杂度为

代码

#include<bits/stdc++.h> 
using namespace std;
#define LL long long
LL read() {
    LL x = 0,f = 0;char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')f=1;ch=getchar();}
    while(isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();}
    return f ? -x : x;
}
const LL mod = 1e9 + 7,N = 1e6 + 1000;
LL X[N],Y[N],inv[N],f[N],t[N],num[N],n;
void add(LL x,LL y) {
    for(LL i = x;i <= n;i+=i&-i) t[i] = (t[i] + y) % mod;
}
LL ask(LL x) {
    LL tot = 0;
    for(LL i = x;i;i -= i&-i) tot = (tot + t[i] + mod) % mod;
    return tot;
}
int main() {
    n = read();
    for(int i = 1;i <= n;i++) {
        int x = read();X[i] = x;Y[x] = read(); 
    }
    inv[0] = inv[1] = 1;
    for(int i = 2;i <= n;i++) inv[i] = (mod - (mod/i) * inv[mod % i] % mod + mod) % mod;
    for(int i = n;i >= 1;i--) {
        num[i] = n - i - ask(Y[i]);add(Y[i],1);
    }
    LL fac = 1;
    for(int i = 1;i < n;i++) fac = fac * i % mod;
    memset(t ,0 ,sizeof(t));
    add(1,1);
    for(int i = 1;i <= n;i++) {
        f[i] = inv[num[i]] * (ask(Y[i])) % mod;
        add(Y[i],f[i]);
    }
    for(int i = 1;i <= n;i++) {
        int id = X[i];
        if(num[id] == 0) printf("%lld\n",f[id] * fac % mod);
        else printf("0\n");
    }
}