5911. 【NOIP2018模擬10.18】Travel
題目大意:
EZ同學家裡非常富有,但又極其的謙虛,說話又好聽,是個不可多得的人才。 EZ常常在假期環遊世界,他準備去N(N<=100000)個國家之多,一些國家有航線連線,由於EZ同學有一定的強迫症,任意兩個國家之間都能通過航路直接或間接到達,並且這樣的路徑僅有一種。(簡單來說,這些國家構成了一棵樹) 由於EZ是C國人,因此將C國(1號國家)作為整棵樹的根 每個國家有一個旅遊熱度A[i]和影響力D[i]。由於目的地有點多,為了避免選擇困難症,他給每個國家設定了一個嚮往值F[i],它等於所有的A[j]之和,滿足i國在j國向C國走D[j]步的路徑上(經過一條航路算一步,i=j也會被統計,如果D[j]步超過了C國,則超出部分不用管)。 LYD同學家裡有礦,富有程度與EZ不相上下,但他卻在宅與現充間搖擺不定。某次機緣巧合,EZ外出旅遊刺激了LYD,他決定也要開始旅遊。為了避免又被判高重複率導致被取消資格,他將EZ的旅遊地圖略微做了一點調整,每條航路將有一定的概率出現。 現在他有Q個詢問,每次詢問某個國家所在的聯通塊(由於每條邊是一定概率出現,因此它所在的聯通塊可以是很多種)中所有國家的F[i]值的和的平方的期望(對998244353取模),以此來決定他旅遊的目的地。但他極其厭惡繁瑣的計算,於是他找到了能算出圓周率並將它倒背下來的你,答應給你豐厚的報酬。家裡沒礦,老爸也不是X達集團老總的你決定接受他的任務。
思路:
先考慮f怎麼求,我們可以在每個點X打上+的標記,在d[i]+1祖宗打上-的標記。然後dfs一次就可以求出來f了,不需要樹剖。 然後考慮則維護合的平方的希望。因為,所以我們要記錄每個子樹的和和每個子樹平方和。然後合併的時候就很簡單了,這樣一次dfs就可以求出f[1]的答案了。 然後怎麼求其他點的答案呢,我們對於一個一個點只要知道他父親過來平方和,和和,然後用字首和優化一下每個兄弟的轉移就好了。
程式:
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LL long long
using namespace std;
const LL N=200005;
const LL mo=998244353;
LL fa[N][21],vd[N],fg[N],fh[N],f[N],g[N],ans[N],last[N],a[N],d[N],t[N],love[N];
LL n,sb,cnt;
struct tree{LL to,next,w;}e[N*2];
LL sqr(LL x){
return (x*x)%mo;
}
void add (LL x,LL y,LL w){
e[++cnt].to=y; e[cnt].next=last[x]; e[cnt].w=w; last[x]=cnt;
e[++cnt].to=x; e[cnt].next=last[y]; e[cnt].w=w; last[y]=cnt;
}
LL dfs(LL x,LL father){
fa[x][0]=father;
LL o=0;
for (LL i=last[x];i;i=e[i].next)
if (e[i].to!=father) o=(o+dfs(e[i].to,x))%mo;
f[x]=(t[x]+o)%mo;
g[x]=sqr(f[x]);
love[x]=f[x];
for (LL i=last[x];i;i=e[i].next)
if (e[i].to!=father){
g[x]=(g[x]+e[i].w*(g[e[i].to]+(2*f[e[i].to])%mo*f[x]%mo))%mo;
f[x]=(f[x]+e[i].w*f[e[i].to])%mo;
}
return t[x]+o;
}
void dfs1(LL x,LL fa,LL fn){
ans[x]=(g[x]+fn*(fg[x]+2*fh[x]*f[x]%mo)%mo)%mo;
LL g1=(sqr(love[x])+fn*(fg[x]+2*fh[x]*love[x]%mo))%mo;
LL h1=(fh[x]*fn+love[x])%mo;
d[0]=0;
for (LL i=last[x];i;i=e[i].next){
LL p=e[i].to;
if (p!=fa){
fg[p]=g1,fh[p]=h1;
g1=(g1+e[i].w*(g[p]+2*h1*f[p]%mo)%mo)%mo;
h1=(h1+e[i].w*f[p])%mo;
d[++d[0]]=p;
vd[d[0]]=e[i].w;
}
}
g1=0,h1=0;
for (LL i=d[0];i>=1;i--){
LL p=d[i];
fg[p]=(fg[p]+g1+2*fh[p]*h1%mo)%mo;
fh[p]=(fh[p]+h1)%mo;
g1=(g1+vd[i]*(g[p]+2*h1*f[p]%mo)%mo)%mo;
h1=(h1+vd[i]*f[p]%mo)%mo;
}
for (LL i=last[x];i;i=e[i].next)
if (e[i].to!=fa) dfs1(e[i].to,x,e[i].w);
}
LL lca(LL x,LL s){
LL i=20;
while (i>=0){
if ((1<<i)<=s) x=fa[x][i],s-=(1<<i);
i--;
}
return x;
}
void shen(int x,int father){
fa[x][0]=father;
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=father) shen(e[i].to,x);
}
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
scanf("%lld",&n);
for (LL i=1;i<=n;i++) scanf("%lld%lld",&a[i],&d[i]);
for (LL i=1;i<n;i++){
LL x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,z);
}
shen(1,0);
for (LL i=1;i<=20;i++)
for (LL j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
for (LL i=1;i<=n;i++){
t[i]=(t[i]+a[i])%mo;
LL u=lca(i,d[i]+1);
t[u]=(t[u]-a[i]+mo)%mo;
}
dfs(1,0);
dfs1(1,0,0);
scanf("%lld",&sb);
for (LL i=1;i<=sb;i++){
LL x;
scanf("%lld",&x);
printf("%lld\n",ans[x]);
}
}