题解:HDU 7439
1. Description
给出长度为 \(n\) 的两个序列 \(f,g\),按照以下方式生成一张图:
for i from 1 to n:
for j from i+1 to n:
if f[i] < f[j] and g[i] < g[j]:
add edge from i to j
else:
add edge from j to i
询问图中有多少个三元环。
2. Solution
这样生成出来的显然是一张竞赛图(在一张无向完全图中给每条边定向得到的有向图),我们在这张图中随意取出三个点,三个点中显然都有边相连,我们只需要保证这些边的方向均正确即可。
考虑边的方向不正确的情况,必定有一个点的出度为 \(2\),换句话说,令一个点的出度为 \(d\),那么先选了这个点,然后再选两个点,不构成三元环的情况有 \(C_d^2\) 种,我们只需要在所有情况中减掉不构成三元环的情况即可。
也就说,答案等于 \(C_n^3-\sum_{i=1}^n C_{d_i}^2\),其中 \(d_i\) 表示点 \(i\) 的出度。
现在我们就把问题转换为了求每个点的出度,显然是两个三维偏序问题.
对于 \(i\),分别考虑 \(j\) 大于 \(i\) 和小于 \(i\) 两种情况:对于 \(j\) 大于 \(i\) 的情况,需要 \(f_j>f_i\) 且 \(g_j>g_i\),对于 \(j\) 小于 \(i\) 的情况,可以先将所有 \(j\) 视为合法的,然后去掉不合法的情况,也就是 \(f_j<f_i\) 且 \(g_j<g_i\) 的情况。
一共做两遍 CDQ 分治即可。
3. Code
/*by qwer6*/
/*略去缺省源和快读快写*/
const int N=2e5+5;
int n;
ll ans;
int f[N],g[N],d[N];
struct Query{
int id,x,y;
bool operator <(const Query &a)const{
return id<a.id;
}
bool operator >(const Query &a)const{
return id>a.id;
}
}a[N],b[N];
struct Binary_tree{
int c[N];
#define lowbit(x) (x&-x)
void add(int x,int v){
for(int i=x;i<=n;i+=lowbit(i))c[i]+=v;
}
int query(int x){
int res=0;
for(int i=x;i;i-=lowbit(i))res+=c[i];
return res;
}
int query(int l,int r){
return query(r)-query(l-1);
}
#undef lowbit
}bit;
void CDQ1(int l,int r){
if(l==r)return ;
int mid=l+r>>1;
CDQ1(l,mid),CDQ1(mid+1,r);
for(int i=l,L=l,R=mid+1;i<=r;i++){
if(R>r||L<=mid&&a[L].x>a[R].x){
b[i]=a[L++];
bit.add(b[i].y,1);
}else{
b[i]=a[R++];
d[b[i].id]+=bit.query(b[i].y+1,n);
}
}
for(int i=l;i<=mid;i++){
bit.add(a[i].y,-1);
a[i]=b[i];
}
for(int i=mid+1;i<=r;i++)a[i]=b[i];
}
void CDQ2(int l,int r){
if(l==r)return ;
int mid=l+r>>1;
CDQ2(l,mid),CDQ2(mid+1,r);
for(int i=l,L=l,R=mid+1;i<=r;i++){
if(R>r||L<=mid&&a[L].x<a[R].x){
b[i]=a[L++];
bit.add(b[i].y,1);
}else{
b[i]=a[R++];
d[b[i].id]-=bit.query(1,b[i].y-1);
}
}
for(int i=l;i<=mid;i++){
bit.add(a[i].y,-1);
a[i]=b[i];
}
for(int i=mid+1;i<=r;i++)a[i]=b[i];
}
signed main(){
read(n);
for(int i=1;i<=n;i++)read(f[i]);
for(int i=1;i<=n;i++)read(g[i]);
for(int i=1;i<=n;i++){
a[i]={i,f[i],g[i]};
d[i]=i-1;
}
sort(a+1,a+n+1,greater<Query>());
CDQ1(1,n);
sort(a+1,a+n+1);
CDQ2(1,n);
ans=1ll*n*(n-1)*(n-2)/6;
for(int i=1;i<=n;i++)
if(d[i]>=2)
ans-=1ll*d[i]*(d[i]-1)/2;
write(ans);
}

浙公网安备 33010602011771号