1. 程式人生 > >5911. 【NOIP2018模擬10.18】Travel

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了,不需要樹剖。 然後考慮則維護合的平方的希望。因為(a+b)2=a2+2ab+b2(a+b)^2=a^2+2*a*b+b^2,所以我們要記錄每個子樹的和和每個子樹平方和。然後合併的時候就很簡單了,這樣一次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]); } }