NOIP2016 天天愛跑步 dsu 樹上差分

2022-05-01 11:06:12 字數 1877 閱讀 3387

題:

題意:給定n個節點的樹和每個節點會在a[i]時刻進行觀察,然後再給出m個點沿從s->t的簡單路徑移動,所有點同時開始且每一秒經過一條邊,問每乙個節點上的觀察員會觀察的幾個點?

分析:我們考慮s到lca(s,t)再到t的路徑,考慮路徑上s到lca(s,t)的點u,要是u能觀察到的充分必要條件就是deep[s]-deep[u]==a[u],所以我們在統計的時候我們把deep[s]加入到桶s中;

對於lca(s,t)到t的路徑上的點同樣的充分必要條件為deep[t]-deep[u]=dis(s,t)-a[u].(化簡一下:deep[s]-2*deep[lca]==a[u]+deep[u]),把答案加到桶t中;

同時,我們要注意到,我們統計是對當前dfs到的點的ans[u]進行統計,有倆部分路勁**,所以要倆部分**都要加到ans[u]上,而我們現在做的相當於在dfs  lca,而lca單單這個點會對倆部分同時計算,這是不正確的(因為一條路徑只有乙個貢獻,而現在你有可能加上了倆個貢獻)。所以要進行差分,具體地就在lca的s桶要消去[deep[s]]的貢獻去(在s的s桶中加什麼就消什麼),在fa[lca]減去[deep[s]-2*deep[lca]]的貢獻

#includeusing

namespace

std;

typedef

long

long

ll;#define pb push_back

const

int m=3e5+5

;inline

intread()

while(ch>='

0'&&ch<='9'

) sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();

return x?sum:-sum;

}inline

void write(int

x)int

n,m;

vector

g[m],signs[m],unsigns[m],signt[m],unsignt[m];

int sz[m],deep[m],son[m],tp[m],s[m],cnt[m<<1],*t=&cnt[m],a[m],vis[m],ans[m],fa[m];

void dfs1(int u,int

ff) }

}void dfs2(int u,int

top)

}int lca(int x,int

y)

return deep[x]>deep[y]?y:x;

}void cal(int u,int

cc)}

void dfs3(int u,int

sign)

if(son[u])

dfs3(son[u],

1),vis[son[u]]=1

; cal(u,1);

if(a[u]+deep[u]<=n)

ans[u]=s[a[u]+deep[u]];

ans[u]+=t[a[u]-deep[u]];

vis[son[u]]=0

;

if(!sign)

cal(u,-1);}

intmain()

dfs1(

1,0);

dfs2(

1,1);

for(int i=1;i<=n;i++)

a[i]=read();

for(int i=1,u,v;i<=m;i++)

dfs3(

1,1);

for(int i=1;i<=n;i++)

write(ans[i]),putchar(''

);

return0;

}

view code

NOIP2016 天天愛跑步

時間限制 2 s 記憶體限制 512 mb 題目描述 小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一棵包含n個結點和n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。...

NOIP2016天天愛跑步

小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 nn n個結點和 n 1n 1n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從11 1到nn...

NOIP2016 天天愛跑步

看這道題不爽很久了,但一直沒有開它,原因是我不會 我太菜了 看了題解還是寫不來,因為我不會線段樹合併。然後今天學了dsu on tree這種神奇的科技,成功把它a了,效率吊打線段樹合併。於是寫篇題解紀念一下。洛谷p1600 天天愛跑步 不帶修改的樹上路徑資訊的維護,很容易想到樹上差分。我們考慮一條路...