传统的延续(树上逆序对)

https://ac.nowcoder.com/acm/contest/12482/J


题意:其实就是求一棵树上,每个点在其对应的链子且在其本身位置之上有多少节点的值>=其本身。

思路:暴力n^2,每个节点跳儿子虽然平均nlogn,但是在链子数据能卡成n^2。出题人的数据显然没构造链子,不然怎么会让n^2水过去了呢.

这玩意dp也不好维护,找位置的关系只能nlogn均摊会被卡。仔细想想,他的值范围在1e5以内,往值上转化。我们可以把树的dfs序的关系看成是一维的,那么对于dfs的过程来说,就是求当前的节点前面有多少>=他的。等价于一维的序列上其节点前面有多少>=他的值的求逆序对的问题。至此就迎刃而解了。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define lowbit(x) x&(-x)
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL tree[maxn];
bool vis[maxn];
vector<LL>g[maxn];
LL val[maxn],ans=0;
void add(LL x,LL d){
    while(x<=100000){
        tree[x]+=d;
        x+=lowbit(x);
    }
}
LL getsum(LL x){
    LL sum=0;
    while(x>0){
       sum+=tree[x];
       x-=lowbit(x);
    }
    return sum;
}
void dfs(LL u,LL cnt){
    add(val[u],1);
    vis[u]=true;
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        dfs(v,cnt+1);
    }
    //cout<<"u="<<u<<" "<<"cnt="<<cnt<<" "<<"getsum(val["<<u<<"])="<<getsum(val[u])<<"\n";
    LL temp=getsum(val[u]-1);
   /// debug(temp);
    ans+=cnt-(temp+1);
    add(val[u],-1);
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,m;cin>>n>>m;
  for(LL i=1;i<=m;i++){
    LL u,v;cin>>u>>v;
    g[u].push_back(v);///反向建边
  }
  for(LL i=1;i<=n;i++) cin>>val[i];
  for(LL i=1;i<=n;i++){
    if(!vis[i]) dfs(i,1);
  }
  cout<<ans<<"\n";
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/115147601