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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

HDU - 6203 ping ping ping(LCA+dfs序+线段树)

發布時間:2024/4/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 6203 ping ping ping(LCA+dfs序+线段树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一棵由n+1個節點組成的數,節點編號為0~n(這個無關緊要,預處理時所有節點以及n都自增1即可轉換為正常的模型了),現在給出m組節點u和v,問若想讓m組u和v都斷開連接,則最少需要去掉幾個點

題目分析:首先我們知道,若想讓u和v斷開連接,最優解肯定是切斷其lca,畢竟是最近公共祖先嘛,當然切斷u和切斷v也可以滿足斷開連接,但并不是最優解,因為切斷lca之后,lca下面的所有不同鏈上的節點都不可能互相到達了,相當于將包含lca在內的子樹從主樹上拿了下來,這樣可以達到切斷一個點,既能滿足u和v斷開連接,也能讓最多的點互不相連

不過這就面臨著一個問題,若切斷了當前的lca,下一組u和v的lca比當前lca的深度要深,那該怎么判斷呢,也就是說下一組的u和v雖然位于當前lca的子樹中,但卻并不受其影響,因為他們的lca比當前的lca深度還要深

這時候我們就可以根據每組u和v的lca的深度進行排序了,優先處理深度大的lca肯定是最優解,因為深度越大的lca所包含的子樹就越小,當處理完深度較大的lca后,用線段樹將其子樹標記一下,在進行后續操作的時候,若u或v中至少有一點被標記過了,說明了被標記的點所在的子樹已經與主樹脫離了,也就是說不需要斷掉任何點就已經無法相互連接了(因為前面斷掉的lca充當了當前u與v的連接點),若u與v都沒有被標記,那么直接斷掉其lca即可,也是有一點貪心的策略

感嘆一下吧,這是上樹一來第一道從有思路開始到實現為止一路通順的題目,一口氣寫完代碼,一遍過樣例,最后1A,還是有點小開心的

這個題的線段樹我看網上很多大佬用樹狀數組代替的,我感覺區別不大,主要是我不會樹狀數組。。所以用線段樹做也是沒什么問題的

代碼:

#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;int n,limit;vector<int>node[N];int deep[N],dp[N][20],L[N],R[N],cnt;//樹上倍增用void dfs(int u,int f,int dep) {L[u]=++cnt;//記錄一下dfs序deep[u]=dep;dp[u][0]=f;for(int i=1;i<=limit;i++)dp[u][i]=dp[dp[u][i-1]][i-1];for(auto v:node[u]){if(v==f)continue;dfs(v,u,dep+1);}R[u]=cnt; }int LCA(int a,int b)//求LCA {if(deep[a]<deep[b])swap(a,b);for(int i=limit;i>=0;i--)if(deep[a]-deep[b]>=(1<<i))a=dp[a][i];if(a==b)return a;for(int i=limit;i>=0;i--)if(dp[a][i]!=dp[b][i]){a=dp[a][i];b=dp[b][i];}return dp[a][0]; }struct Node {int u,v,lca;bool operator<(const Node& a)const{return deep[lca]>deep[a.lca];} }a[N*5];struct tree {int l,r;bool lazy; }tree[N<<2];//線段樹維護一個lazy標記即可void pushdown(int k) {tree[k<<1].lazy=tree[k<<1|1].lazy=true;tree[k].lazy=false; }void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;tree[k].lazy=false;if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); }void update(int k,int l,int r) {if(tree[k].r<l||tree[k].l>r)return;if(tree[k].l>=l&&tree[k].r<=r){tree[k].lazy=true;return;}if(tree[k].lazy)pushdown(k);update(k<<1,l,r);update(k<<1|1,l,r); }bool query(int k,int pos) {if(tree[k].l==tree[k].r)return tree[k].lazy;if(tree[k].lazy)pushdown(k);int mid=tree[k].l+tree[k].r>>1;if(mid>=pos)return query(k<<1,pos);elsereturn query(k<<1|1,pos); }void init() {for(int i=1;i<=n;i++)node[i].clear();limit=log2(n)+1;cnt=0; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);while(scanf("%d",&n)!=EOF){n++;init();for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);u++,v++;node[u].push_back(v);node[v].push_back(u);}dfs(1,0,0);build(1,1,n);int m;scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%d%d",&a[i].u,&a[i].v);a[i].u++,a[i].v++;a[i].lca=LCA(a[i].u,a[i].v);}sort(a+1,a+1+m);int ans=0;for(int i=1;i<=m;i++){if(query(1,L[a[i].u])||query(1,L[a[i].v]))//如果u和v至少有一個被標記過了,說明已經互不相連了continue;else//若都沒被標記過,斷掉其lca{ans++;update(1,L[a[i].lca],R[a[i].lca]);}}printf("%d\n",ans);}return 0; }

?

總結

以上是生活随笔為你收集整理的HDU - 6203 ping ping ping(LCA+dfs序+线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。

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