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

傳送門: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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章