JZOJ 5956. 【NOIP2018模拟11.7A组】easy LCA
Description
Input
Output
輸出一行一個(gè)整數(shù),表示所求的所有連續(xù)子段的權(quán)值和。
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
-
這題做法多種多樣,什么線段樹合并、分治……
-
我用的方法比較簡單好打,用個(gè)單調(diào)棧就好了。
-
我們先對相鄰兩點(diǎn)求出其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])
-
這個(gè)我用的是樹鏈剖分求lca,跑得比較快一些。
-
于是我們就得到了 n?1n-1n?1 個(gè)點(diǎn)。
-
易知一段區(qū)間的點(diǎn)的lca就是對應(yīng)的一段 a[i]a[i]a[i] 中深度最小的那個(gè)。
-
那么我們對于每個(gè) a[i]a[i]a[i] 計(jì)算其作為最終lca的答案。
-
(一個(gè) a[i]a[i]a[i] 對應(yīng)著兩個(gè)點(diǎn),所以答案最終還要加上 ∑dep[p[i]]\sum dep[p[i]]∑dep[p[i]])
-
對于每個(gè) a[i]a[i]a[i] ,我們希望求出 l[i]l[i]l[i] ,表示以它為lca的一段點(diǎn)最左能擴(kuò)展到哪里。
-
于是我們維護(hù)一個(gè)單調(diào)上升 aaa 的棧,遇到一個(gè)新的 a[i]a[i]a[i] ,就把比 a[i]a[i]a[i] 大的都退掉,剩下位置就相當(dāng)于是 l[i]l[i]l[i] 了。
-
同樣的,我們也求出 r[i]r[i]r[i] 表示最右到哪兒,注意由于 a[i]a[i]a[i] 可能相等,為了不算重,我們可以在算 r[i]r[i]r[i] 退棧時(shí)把大于改為大于等于,算 l[i]l[i]l[i] 仍是大于,這樣就解決這個(gè)問題了。
-
那么最后答案就是:∑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=1∑n?1?dep[a[i]]?(i?l[i])?(r[i]?i)+i=1∑n?dep[p[i]]
-
時(shí)間復(fù)雜度 O(nlogn)O(n\ log\ n)O(n?log?n) ,這個(gè) log 是算 lca 時(shí)帶的,如果用 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; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 5956. 【NOIP2018模拟11.7A组】easy LCA的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NOIP2018 赛前集训总结反思
- 下一篇: NOIP2018比赛总结