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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

P5327 [ZJOI2019]语言

發布時間:2023/12/3 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P5327 [ZJOI2019]语言 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

?P5327 [ZJOI2019]語言

題目描述

詳見:P5327?[ZJOI2019]語言

簡要題意:給定一棵樹和一些鏈,問樹上處于同一條鏈的不同點對數。

Solution

對于每一個點,考慮以它為端點的可行路徑有哪些。

我們可以發現,可以到達的節點會組成一個斯坦納樹,這棵斯坦納樹包含了即經過鏈。

我們進一步可知,這棵斯坦納樹就是以和經過的所有鏈的端點為關鍵點的最小斯坦納樹。

所以我們考慮對于每一個點,維護經過它的鏈組成的斯坦納樹是什么,順便維護答案(斯坦納樹的邊數)。

?

事實上,斯坦納樹的邊數就是其中所有點的深度-dfs序相鄰的點的LCA的深度,如下:

設斯坦納樹的點集為,記的dfs序為??,深度為??? 。

若滿足??? ,即dfs序按升序排序,則

?

可以用線段樹合并(啟發式合并也可)支持上述信息的維護。

線段樹的下標為??,并記錄??? 中最大的點,?最小的點,以及?? 。

合并時? ?。

統計答案時???

?

因此,對于每一條路徑??? ,我們可以用樹上差分把它拆成??? 這四條代價分別為+1,+1,-1,-1的鏈,分別放入權值線段樹,并不斷向上合并到根,沿路統計答案即可。

表實現LCA,時間復雜度??。

如果寫倍增LCA的會多一個,卡卡常應該也能過。

?

PS:這道題寫了1h,調了5h,原因是線段樹動態開點要開log倍的內存。但我一直以為是dfs爆棧了(因為今早有一題先例),由于要用到dfs序,所以甚至在try coding 手工棧,However,WA聲依舊,改得代碼奇丑無比,自閉了一個下午,最后柳暗花明又一村,有一種想右轉直行的沖動。

Code

最后貼一個丑陋的代碼(早把罪惡的手工棧刪了)。

#include<bits/stdc++.h> #define RG register typedef long long ll; const int MAXN=4e5+50; std::vector<int> e[MAXN],Del[MAXN]; int DFN=0,t=0,n,m; int dfn[MAXN],st[MAXN][21],fa[MAXN]; int pre[MAXN],rt[MAXN],Log[MAXN]; ll dep[MAXN],ans=0; inline int read() {RG int x=0,f=1; char c=getchar();while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f; } inline void get_dfn(int x,int father) {dfn[x]=++DFN;pre[x]=++t; st[t][0]=x;fa[x]=father; dep[x]=dep[father]+1;for (RG int i=0;i<e[x].size();i++)if (e[x][i]!=fa[x]) get_dfn(e[x][i],x),st[++t][0]=x; } inline void get_st() {Log[1]=0;for (RG int i=2;i<=t;i++) Log[i]=Log[i>>1]+1;for (RG int i=1;i<=Log[t];i++)for (RG int j=1;j<=t-(1<<i)+1;j++) st[j][i]=dep[st[j][i-1]]<dep[st[j+(1<<(i-1))][i-1]]?st[j][i-1]:st[j+(1<<(i-1))][i-1]; } inline int get_lca(int x,int y) {x=pre[x],y=pre[y];if (x>y) std::swap(x,y);RG int k=Log[y-x+1];return std::max(1,dep[st[x][k]]<dep[st[y-(1<<k)+1][k]]?st[x][k]:st[y-(1<<k)+1][k]); } struct Segment_Tree {int segnum=0;struct treenode{int lson,rson,fi,la; ll sum,ans; } tree[MAXN<<4];#define lft tree[x].lson#define rht tree[x].rsoninline void up(int x){RG int lca=get_lca(tree[lft].la,tree[rht].fi);//cout<<lft<<" "<<rht<<" "<<lca<<endl;tree[x].ans=tree[lft].ans+tree[rht].ans-dep[lca];tree[x].fi=tree[lft].fi?tree[lft].fi:tree[rht].fi;tree[x].la=tree[rht].la?tree[rht].la:tree[lft].la;}inline void change(int &x,int p,int v,int L,int R){if (!x) x=++segnum;if (L==R){tree[x].sum+=v;tree[x].ans=tree[x].sum?dep[p]:0;tree[x].la=tree[x].fi=tree[x].sum?p:0;return;}RG int mid=(L+R)>>1;if (dfn[p]<=mid) change(lft,p,v,L,mid);else change(rht,p,v,mid+1,R);up(x);}inline ll query(int x){ RG int lca=get_lca(tree[x].la,tree[x].fi);return tree[x].ans-dep[lca];}inline void merge(int &x,int v,int L,int R){if (!x||!v) { x|=v; return; }if (L==R){tree[x].sum+=tree[v].sum;tree[x].ans|=tree[v].ans;tree[x].la|=tree[v].la;tree[x].fi|=tree[v].fi;return;}RG int mid=(L+R)>>1;merge(lft,tree[v].lson,L,mid);merge(rht,tree[v].rson,mid+1,R);up(x);} } segment; inline void solve(int x) {for (RG int i=0;i<e[x].size();i++)if (e[x][i]!=fa[x]) solve(e[x][i]);for (RG int i=0;i<Del[x].size();i++) segment.change(rt[x],Del[x][i],-1,1,n);ans+=segment.query(rt[x]);//cout<<ans<<endl;if (fa[x]) segment.merge(rt[fa[x]],rt[x],1,n); } int main() {//freopen("a.in","r",stdin);n=read(),m=read();for (RG int i=1;i<n;i++){int u=read(),v=read();e[u].push_back(v);e[v].push_back(u);}dep[0]=-1;get_dfn(1,0);get_st();for (RG int i=1;i<=m;i++) {RG int u=read(),v=read(),lca=get_lca(u,v);//cout<<lca<<endl;segment.change(rt[u],v,1,1,n); segment.change(rt[v],u,1,1,n); segment.change(rt[v],v,1,1,n); segment.change(rt[u],u,1,1,n); //segment.change(rt[lca],u,-1,1,n); segment.change(rt[lca],v,-1,1,n);//if (fa[lca]) segment.change(rt[fa[lca]],u,-1,1,n),segment.change(rt[fa[lca]],v,-1,1,n);//cout<<lca<<endl;Del[lca].push_back(u),Del[lca].push_back(v);if (fa[lca]) Del[fa[lca]].push_back(u),Del[fa[lca]].push_back(v);}solve(1);printf("%lld\n",ans>>1);return 0; } /* 12 4 1 2 2 3 2 4 4 5 1 6 6 7 6 8 6 9 9 10 9 11 1 124 12 8 10 7 11 3 10 */

還附加了一個小樣例,然而樣例輸出咕了。

總結

以上是生活随笔為你收集整理的P5327 [ZJOI2019]语言的全部內容,希望文章能夠幫你解決所遇到的問題。

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