日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JZOJ 5956. 【NOIP2018模拟11.7A组】easy LCA

發布時間:2025/3/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JZOJ 5956. 【NOIP2018模拟11.7A组】easy LCA 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Description

Input

Output

輸出一行一個整數,表示所求的所有連續子段的權值和。

Sample Input

6
1 2
2 6
6 3
3 4
6 5
1 2 3 4 5 6

Sample Output

51

Data Constraint

Solution

  • 這題做法多種多樣,什么線段樹合并、分治……

  • 我用的方法比較簡單好打,用個單調棧就好了。

  • 我們先對相鄰兩點求出其lca,即:a[i]=lca(p[i],p[i+1])a[i]=lca(p[i],p[i+1])a[i]=lca(p[i],p[i+1])

  • 這個我用的是樹鏈剖分求lca,跑得比較快一些。

  • 于是我們就得到了 n?1n-1n?1 個點。

  • 易知一段區間的點的lca就是對應的一段 a[i]a[i]a[i] 中深度最小的那個。

  • 那么我們對于每個 a[i]a[i]a[i] 計算其作為最終lca的答案。

  • (一個 a[i]a[i]a[i] 對應著兩個點,所以答案最終還要加上 ∑dep[p[i]]\sum dep[p[i]]dep[p[i]]

  • 對于每個 a[i]a[i]a[i] ,我們希望求出 l[i]l[i]l[i] ,表示以它為lca的一段點最左能擴展到哪里。

  • 于是我們維護一個單調上升 aaa 的棧,遇到一個新的 a[i]a[i]a[i] ,就把比 a[i]a[i]a[i] 大的都退掉,剩下位置就相當于是 l[i]l[i]l[i] 了。

  • 同樣的,我們也求出 r[i]r[i]r[i] 表示最右到哪兒,注意由于 a[i]a[i]a[i] 可能相等,為了不算重,我們可以在算 r[i]r[i]r[i] 退棧時把大于改為大于等于,算 l[i]l[i]l[i] 仍是大于,這樣就解決這個問題了。

  • 那么最后答案就是:∑i=1n?1dep[a[i]]?(i?l[i])?(r[i]?i)+∑i=1ndep[p[i]]\sum_{i=1}^{n-1}dep[a[i]]*(i-l[i])*(r[i]-i)+\sum_{i=1}^{n}dep[p[i]]i=1n?1?dep[a[i]]?(i?l[i])?(r[i]?i)+i=1n?dep[p[i]]

  • 時間復雜度 O(nlogn)O(n\ log\ n)O(n?log?n) ,這個 log 是算 lca 時帶的,如果用 tarjan 求 lca 可以做到線性(但聽說跑得沒有樹鏈剖分快)。

Code

#include<cstdio> #include<cctype> using namespace std; typedef long long LL; const int N=6e5+5; int n,tot; LL ans; int first[N],nex[N<<1],en[N<<1]; int dep[N],size[N],son[N],top[N],fa[N]; int p[N],a[N],st[N],l[N],r[N]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } inline void insert(int x,int y) {nex[++tot]=first[x];first[x]=tot;en[tot]=y; } void dfs(int x) {dep[x]=dep[fa[x]]+1;size[x]=1;for(int i=first[x];i;i=nex[i])if(en[i]^fa[x]){fa[en[i]]=x;dfs(en[i]);size[x]+=size[en[i]];if(size[son[x]]<size[en[i]]) son[x]=en[i];} } void dfs1(int x,int y) {top[x]=y;if(!son[x]) return;dfs1(son[x],y);for(int i=first[x];i;i=nex[i])if(en[i]^fa[x] && en[i]^son[x]) dfs1(en[i],en[i]); } inline int lca(int x,int y) {while(top[x]^top[y])if(dep[top[x]]>dep[top[y]]) x=fa[top[x]]; else y=fa[top[y]];return dep[x]<dep[y]?x:y; } int main() {freopen("easy.in","r",stdin);freopen("easy.out","w",stdout);n=read();for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}dfs(1);dfs1(1,1);for(int i=1;i<=n;i++){p[i]=read();ans+=dep[p[i]];}for(int i=1;i<n;i++) a[i]=dep[lca(p[i],p[i+1])];tot=0;for(int i=1;i<n;i++){while(tot && a[st[tot]]>=a[i]) tot--;l[i]=st[tot];st[++tot]=i;}st[tot=0]=n;for(int i=n-1;i;i--){while(tot && a[st[tot]]>a[i]) tot--;r[i]=st[tot];st[++tot]=i;}for(int i=1;i<n;i++) ans+=(LL)a[i]*(i-l[i])*(r[i]-i);printf("%lld",ans);return 0; }

總結

以上是生活随笔為你收集整理的JZOJ 5956. 【NOIP2018模拟11.7A组】easy LCA的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。