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;
}