題:
題意:給定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]]的貢獻
#includeusingview codenamespace
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;
}
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 天天愛跑步 不帶修改的樹上路徑資訊的維護,很容易想到樹上差分。我們考慮一條路...