树上差分例2 [ JLOI2014 ] 松鼠的新家 [ luogu P3258 ]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/violinlove/article/details/83218521

传送门:https://www.luogu.org/problemnew/show/P3258

咱们都知道树上查分+lca妙用太多了,这要是真的考到了,咋推得出来呢?

也许语文没学好,输入全错了,然过了样例(样例太水了,哇啦哇啦,交之后0分了3回-_-

那就积累一波吧::用本来确定的知识然后进行一些改动!!!

例如加减一些确定的ans

而不是先考虑自创算法啊~毕竟对树上差分都是囫囵吞枣地学。。。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

inline int wread(){
    char c=getchar ();int flag=1,wans=0;
    while (c<'0'||c>'9'){if (c=='-') flag=-1;c=getchar ();}
    while (c>='0'&&c<='9'){wans=wans*10+c-'0';c=getchar ();}
    return wans*=flag;
}

inline void OUT (int x){
    if (x>9)	OUT(x/10);
    putchar (x%10+'0');
}

int n;
int a[300006],b[300006];
int K,hed[300006];
struct node{int v,nxt;}e[600005];
inline void ad (int u,int v){
    e[++K]=(node){v,hed[u]};hed[u]=K;
}

int p[300005][21];
int dep[300005];
int ans[300005];

void dfs (int x,int fa){
    p[x][0]=fa;
    for (register int i(1);i<=20;++i)	p[x][i]=p[p[x][i-1]][i-1];
    for (register int i(hed[x]);i!=-1;i=e[i].nxt){
        int v(e[i].v);
        if (v==fa)	continue;
        dep[v]=dep[x]+1;
        dfs (v,x);
    }
    return ;
}

int lca (int a,int b){
    if (dep[a]>dep[b])	swap (a,b);
    for (register int i(20);i>=0;--i)
        if (dep[a]<=dep[p[b][i]])	b=p[b][i];
    if (a==b)	return a;
    for (register int i(20);i>=0;--i){
        if (p[a][i] == p[b][i])	continue;
        a=p[a][i];b=p[b][i];
    }
    return p[a][0];
}

void getans (int x,int fa){
    for (register int i(hed[x]);i!=-1;i=e[i].nxt){
        int v(e[i].v);
        if (v==fa)	continue;
        getans(v,x);
        ans[x]+=ans[v];
    }
    return ;
}

int main (){
    memset (hed,-1,sizeof hed); 
    n=wread();
    for (register int i(1);i<=n;++i)
        a[i]=wread();
    for (register int i(1);i<n;++i){
        int u(wread()),v(wread());
        ad (u,v);ad(v,u);
    }
    dep[1]=1;
    dfs (1,0);
    for (register int i(1);i<n;++i){
        int lcai(lca(a[i],a[i+1]));
        ans[a[i]]++;
        ans[a[i+1]]++;
        ans[lcai]--;
        ans[p[lcai][0]]--;
        //覆盖i~i+1路径上所有的点
		//包括i和i+1
		//显然会重复,于是后面减回来 
    }
    getans (1,0);
    for (int i(2);i<=n;++i)
        ans[a[i]]--;//减去多加上的&最后一个a[n](因为最后一个到了餐厅,不用糖果) 
    for (int i(1);i<=n;++i){
        OUT(ans[i]);putchar ('\n');
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/violinlove/article/details/83218521
今日推荐