P3605 [USACO17JAN]Promotion Counting P dfs序

传送门

文章目录

题意:

在这里插入图片描述

思路:

这个题可以用各种姿势a掉,树启和线段树合并都可以,比较无脑。下面给一个解决这种问题比较巧妙的做法。
考虑暴力怎么写,我们先将每个点的权值离散化一下,每到一个点就把树状数组清空,让后在树状数组中加上这个子树的值,用树状数组查询 p j > p i p_j>p_i pj>pi的数量。
我们优化以上算法,还是先离散化,也是用到了树状数组。
考虑对于一个点,当 d f s dfs dfs遍历这个点会遍历两次 ,第一次是从父亲节点到这个点,第二次是从他的子节点回溯回来。我们在回溯的时候加上这个节点的权值,那么当回溯到这个点的时候,树状数组中存的值包含了以这个点为根的子树的全部权值,当然里面可能还有别的点的值(即"垃圾"值),如果我们按照之前一遍一清空的话复杂度是 O ( n 2 ) O(n^2) O(n2)的,我们就是要优化这里。现在想想,如果能把树状数组中那些”垃圾“值减去不就行了吗?我们如何才能知道那些值呢?我们惊奇的发现第一次到这个点的时候树状数组中存的不就是这个值嘛?所以我们定义一个 a n s ans ans,第一次到这个点的时候减去 s u m ( s e ) − s u m ( a [ u ] ) sum(se)-sum(a[u]) sum(se)sum(a[u]),回溯的时候加上 s u m ( s e ) − s u m ( a [ u ] ) sum(se)-sum(a[u]) sum(se)sum(a[u])即可,这个时候即为答案啦。

//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
#define lowbit(x) ((x)&(-x))
using namespace std;

//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int N=1000010,M=N*2,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,se;
int a[N];
vector<int>v;
int tr[N];
int e[M],ne[M],h[N],idx;
int ans[N];

void add(int a,int b)
{
    
    
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void addd(int x,int c)
{
    
    
    for(int i=x;i<=se;i+=lowbit(i)) tr[i]+=c;
}

int sum(int x)
{
    
    
    int ans=0;
    for(int i=x;i;i-=lowbit(i)) ans+=tr[i];
    return ans;
}

int find(int x)
{
    
    
    return lower_bound(v.begin(),v.end(),x)-v.begin();
}

void dfs(int u)
{
    
    
    ans[u]-=sum(se)-sum(a[u]);
    for(int i=h[u];~i;i=ne[i]) {
    
     int ver=e[i]; dfs(ver); }
    ans[u]+=sum(se)-sum(a[u]);
    addd(a[u],1);
}

int main()
{
    
    
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    scanf("%d",&n);
    memset(h,-1,sizeof(h)); idx=0;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.pb(a[i]);
    sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end());
    se=v.size();
    for(int i=1;i<=n;i++) a[i]=find(a[i])+1;
    for(int i=2;i<=n;i++)
    {
    
    
        int x; scanf("%d",&x);
        add(x,i);
    }
    dfs(1);
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);


	return 0;
}
/*

*/






猜你喜欢

转载自blog.csdn.net/m0_51068403/article/details/115043865
今日推荐