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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

环套树

發布時間:2024/8/26 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 环套树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

bzoj1040 騎士

題目大意:給出每個騎士的攻擊力和痛恨的人,每個騎士不能和自己痛恨的人一起出現,選一些騎士使得他們的攻擊力最大。

思路:因為每個騎士恨一個人,所以是一個環套樹森林(注意n點n邊的聯通圖可能是環套樹森林!!!),雖然題目是單向邊,但等同于雙向邊。對于環套樹dp的做法,可以搜到環后,把環從一處斷開,對于這道題目,對斷開后的兩點分別為根做樹型dp(要求根不能選),加給答案。但是要注意二元環的情況,我們可以對于二元環只加一次無向邊(其實是兩條有向邊),因為二元環完全可以當作有邊相連的兩點處理,這個時候可能會出現一棵沒有環的樹,我們需要在退回到dfs起點的那個點的時候人為的做一下dp。

一定要十分注意二元環的情況!!!

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define maxnode 1000005 using namespace std; int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},tot=0,x=0,y=0,ai[maxnode]={0}; LL val[maxnode]={0},f[maxnode][2]={0},ans=0; bool visit[maxnode]={false},ff; void add(int u,int v) {++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;++tot;next[tot]=point[v];point[v]=tot;en[tot]=u; } void dp(int u,int fa) {int i,j;f[u][1]=val[u];visit[u]=true;for (i=point[u];i;i=next[i]){if (en[i]!=fa){if ((u==y&&en[i]==x)||(u==x&&en[i]==y)) continue;dp(en[i],u);f[u][0]+=max(f[en[i]][0],f[en[i]][1]);f[u][1]+=f[en[i]][0];}} } void dfs(int u,int fa) {int i,j;LL ci=0;visit[u]=true;for (i=point[u];i;i=next[i]){if (en[i]!=fa){if (visit[en[i]]){x=u;y=en[i];memset(f,0,sizeof(f));dp(x,y);ci=max(ci,f[x][0]);memset(f,0,sizeof(f));swap(x,y);dp(x,y);ci=max(ci,f[x][0]);ans+=ci;ff=true;return;}else{dfs(en[i],u);if (ff) return;}}}if (fa==0){x=y=0;dp(u,0);ans+=max(f[u][0],f[u][1]);} } int main() {int n,i,j;scanf("%d",&n);for (i=1;i<=n;++i) scanf("%I64d%d",&val[i],&ai[i]);for (i=1;i<=n;++i)if (ai[ai[i]]!=i||ai[i]>i) add(i,ai[i]);for (i=1;i<=n;++i)if (!visit[i]){ff=false;dfs(i,0);}printf("%I64d\n",ans); } View Code

?

bzoj2878 迷失游樂園(!!

題目大意:給出一棵環套樹,隨機選一個點開始走,等概率走向周圍沒有經過的點,問走的路徑長度期望。

思路:樹上的比較好求,從終點開始走,更新出每個點的up和down,gi[u][0]=sigma 1/(du[u]-1)*(gi[v][0]+va[i]),最后一個點的時候(也就是起點)是/du[u]。有環的時候,先找出所有外向樹的up,用這個up去更新其他的up(中間要用另一個數組存,防止改變最初的up)。有環的時候的概率是(gi[u][0]+ci*(du[u]-2)/(du[u]-1))*cc。cc表示環上選這條路徑的概率,ci表示環上鏈的權值和,ci后面乘的式子是因為外向樹中所帶來的概率的和不是樹上的(du[u]-1)/du[u],而是(du[u]-2)/du[u],所以有所改變。對于環上相鄰兩點繞了一圈的情況終點的處的概率是1/(du[u]-2),因為環上的兩個點都不能走。

注意:一定要考慮好概率的轉移和環上相鄰點的特殊情況。

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 100005 #define M 200005 #define LD double #define eps 1e-9 using namespace std; int in(){char ch=getchar();int x=0;while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x;} int cmp(LD x,LD y){if (x-y>eps) return 1;if (y-x>eps) return -1;return 0;} int n,m,rt,point[N]={0},next[M],en[M],tot,du[N]={0},fe[N]={0},hu[N],hz=0,zh[N],zt=0; LD va[M],fi[N],gi[N][2],hv[N]; bool oh[N]={false},hh=false,vi[N]={false}; void add(int u,int v,LD w){next[++tot]=point[u];point[u]=tot;en[tot]=v;va[tot]=w;next[++tot]=point[v];point[v]=tot;en[tot]=u;va[tot]=w;++du[u];++du[v]; } void up(int u,int fa){int i,v;gi[u][0]=0.;for (i=point[u];i;i=next[i]){if ((v=en[i])==fa) continue;up(v,u);gi[u][0]+=1./(du[u]-1)*(gi[v][0]+va[i]);} } void down(int u,int fa,LD vv){int i,v;fi[u]=0.;gi[u][1]=gi[u][0];if (fa){fi[u]+=1./du[u]*(gi[fa][1]-(1./(du[fa]-1)*(gi[u][0]+vv))+vv);if (du[u]>1) gi[u][1]+=1./(du[u]-1)*(gi[fa][1]-(1./(du[fa]-1)*(gi[u][0]+vv))+vv);}for (i=point[u];i;i=next[i]){if ((v=en[i])==fa) continue;down(v,u,va[i]);fi[u]+=1./du[u]*(gi[v][0]+va[i]);} } void geth(int x){hz=0;for (;;--zt){oh[zh[zt]]=true;hu[++hz]=zh[zt];hv[hz]=va[fe[zh[zt]]];if (zh[zt]==x) break;} } void find(int u){int i,v;zh[++zt]=u;vi[u]=true;for (i=point[u];i;i=next[i]){v=en[i];if (i==fe[u]||(i==(fe[u]^1))) continue;if (vi[v]){geth(v);hh=true;hv[hz]=va[i];return;}fe[v]=i;find(v);if (hh) return;}--zt; } void gup(int u){int i,v;gi[u][0]=0.;vi[u]=true;for (i=point[u];i;i=next[i]){if (vi[v=en[i]]) continue;gup(v);gi[u][0]+=1./(du[u]-1)*(gi[v][0]+va[i]);} } void gdown(int u,int fa,LD vv){int i,v;gi[u][1]=gi[u][0];if (fa){fi[u]+=1./du[u]*(gi[fa][1]-(1./(du[fa]-1)*(gi[u][0]+vv))+vv);if (du[u]>1) gi[u][1]+=1./(du[u]-1)*(gi[fa][1]-(1./(du[fa]-1)*(gi[u][0]+vv))+vv);}for (i=point[u];i;i=next[i]){v=en[i];if (oh[v]||v==fa) continue;gdown(v,u,va[i]);fi[u]+=1./du[u]*(gi[v][0]+va[i]);} } int main(){int i,j,u,v,w,la;LD ans=0.,ci,cc;n=in();m=in();tot=1;for (i=1;i<=m;++i){u=in();v=in();w=in();add(u,v,(LD)w);}if (m==n-1){for (i=1;i<=n;++i)if (du[i]>1){rt=i;break;}up(rt,0);down(rt,0,0.);for (i=1;i<=n;++i) ans+=1./n*fi[i];}else{find(1);for (i=1;i<=n;++i){vi[i]=oh[i];fi[i]=gi[i][0]=gi[i][1]=0.;}for (i=1;i<=n;++i)if (oh[i]) gup(i);for (i=1;i<=hz;++i){u=hu[i];ci=0.;cc=1.;gi[u][1]+=gi[u][0];for (la=i,j=i%hz+1;j!=i;la=j,j=j%hz+1){ci+=hv[la];cc/=1.*(du[hu[j]]-1);if (cmp(gi[u][0],0.)>0){if (j%hz+1!=i){fi[hu[j]]+=(gi[u][0]+ci*(du[u]-2)/(du[u]-1))*cc*(du[hu[j]]-1)/du[hu[j]];gi[hu[j]][1]+=(gi[u][0]+ci*(du[u]-2)/(du[u]-1))*cc;}else{fi[hu[j]]+=(gi[u][0]*(du[u]-1)/(du[u]-2)+ci)*cc*(du[hu[j]]-1)/du[hu[j]];gi[hu[j]][1]+=(gi[u][0]*(du[u]-1)/(du[u]-2)+ci)*cc;}}}if (du[u]==2){fi[hu[la]]+=ci*cc*(du[hu[la]]-1)/du[hu[la]];gi[hu[la]][1]+=ci*cc;}ci=0.;cc=1.;for (la=i,j=(i==1 ? hz : i-1);j!=i;la=j,j=(j==1 ? hz : j-1)){ci+=hv[j];cc/=1.*(du[hu[j]]-1);if (cmp(gi[u][0],0.)>0){if ((j==1 ? hz : j-1)!=i){fi[hu[j]]+=(gi[u][0]+ci*(du[u]-2)/(du[u]-1))*cc*(du[hu[j]]-1)/du[hu[j]];gi[hu[j]][1]+=(gi[u][0]+ci*(du[u]-2)/(du[u]-1))*cc;}else{fi[hu[j]]+=(gi[u][0]*(du[u]-1)/(du[u]-2)+ci)*cc*(du[hu[j]]-1)/du[hu[j]];gi[hu[j]][1]+=(gi[u][0]*(du[u]-1)/(du[u]-2)+ci)*cc;}}}if (du[u]==2){fi[hu[la]]+=ci*cc*(du[hu[la]]-1)/du[hu[la]];gi[hu[la]][1]+=ci*cc;}}for (i=1;i<=n;++i)if (oh[i]){gi[i][0]=gi[i][1];gi[i][1]=0.;}for (i=1;i<=n;++i)if (oh[i]) gdown(i,0,0.);for (i=1;i<=n;++i) ans+=1./n*fi[i];}printf("%.5f\n",ans); } View Code

?

bzoj3242 快餐店

題目大意:給出一棵環套樹,在某個位置(邊或點上)放一個快餐店,使得最遠點到這個店的距離最小,輸出最小距離。

思路:可以證明方案中一定有一條環上的邊不經過(邊左右的點分別經過左右到那個快餐店或者快餐店所在外向樹的根!!。所以可以刪掉一條邊之后,求出樹的直徑/2就是答案,考慮快速求這個直徑。如果在外向樹上,是不變的,可以dp出一個值mx(這一部分不要忘記!!)。經過環的話,是不相同的兩點i、j,距離是max(sm[i]-sm[j]+fi[i]+fi[j]),sm[i]表示不選邊的一端為起點的邊權和,fi[i]表示i這個點外向樹從根出去的最長鏈,可以維護最大的sm[i]+fi[i],最小的sm[i]-fi[i],因為i和j不能相同,維護出次大次小值,求的時候判斷一下。取刪掉不同邊的直徑的最小值。

注意:1)分清最大最小值:外向樹上的直徑是要和環上直徑取max的;環上求直徑的時候,如果最大最小值的i一樣,用最大次小和最小次大的較大值更新;

   2)這里的sum只需要求相對差就可以了,不用區間修改,只需要用上一個+邊權更新這一個就可以了。

#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define N 100005 #define M 200005 #define LL long long #define mid (l+r)/2 #define lson i<<1,l,mid #define rson i<<1|1,mid+1,r #define inf 1000000000000000000LL using namespace std; int in(){char ch=getchar();int x=0;while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x;} int point[N]={0},next[M],en[M],tot=0,zh[N],zt=0,hu[N],hz,fe[N]={0}; LL hv[N],va[M],fi[N]={0},dis[N]={0},sm[N]={0},ld=0LL,gi[N]={0}; bool vi[N]={false},oh[N]={false},f=false; void add(int u,int v,LL w){next[++tot]=point[u];point[u]=tot;en[tot]=v;va[tot]=w;next[++tot]=point[v];point[v]=tot;en[tot]=u;va[tot]=w; } void geth(int x){for (hz=0;;--zt){hu[++hz]=zh[zt];oh[zh[zt]]=true;hv[hz]=va[fe[zh[zt]]];if (zh[zt]==x) break;} } void dfs(int u,int fa){int i,v;vi[u]=true;zh[++zt]=u;for (i=point[u];i;i=next[i]){if ((v=en[i])==fa) continue;if (vi[v]){geth(v);f=true;hv[hz]=va[i];return;}fe[v]=i;dfs(v,u);if (f) return;}--zt; } void getf(int u,int anc){int i,v;LL mx=0LL,cmx=0LL,vv;vi[u]=true;gi[u]=0LL;fi[anc]=max(fi[anc],dis[u]);for (i=point[u];i;i=next[i]){if (vi[v=en[i]]) continue;dis[v]=dis[u]+va[i];getf(v,anc);vv=gi[v]+va[i];gi[u]=max(gi[u],vv);if (vv>=mx){cmx=mx;mx=vv;}else if (vv>=cmx) cmx=vv;}ld=max(ld,mx+cmx); } struct use{LL mx,mn,cmx,cmn;int px,pn,cpx,cpn;}tr[N<<2]; use updata(use x,use y){if (y.mx>=x.mx){x.cmx=x.mx;x.cpx=x.px;x.mx=y.mx;x.px=y.px;}else if (y.mx>=x.cmx){x.cmx=y.mx;x.cpx=y.px;}if (y.cmx>=x.cmx){x.cmx=y.cmx;x.cpx=y.cpx;}if (y.mn<=x.mn){x.cmn=x.mn;x.cpn=x.pn;x.mn=y.mn;x.pn=y.pn;}else if (y.mn<=x.cmn){x.cmn=y.mn;x.cpn=y.pn;}if (y.cmn<=x.cmn){x.cmn=y.cmn;x.cpn=y.cpn;}return x;} void build(int i,int l,int r){if (l==r){tr[i]=(use){sm[l]+fi[l],sm[l]-fi[l],-inf,inf,l,l,0,0};return;}build(lson);build(rson);tr[i]=updata(tr[i<<1],tr[i<<1|1]); } void tch(int i,int l,int r,int x){if (l==r){tr[i]=(use){sm[l]+fi[l],sm[l]-fi[l],-inf,inf,l,l,0,0};return;}if (x<=mid) tch(lson,x);else tch(rson,x);tr[i]=updata(tr[i<<1],tr[i<<1|1]); } int main(){int n,i,j,k,u,v,w;LL ans=inf;use ci;n=in();for (i=1;i<=n;++i){u=in();v=in();w=in();add(u,v,(LL)w);}dfs(1,0);for (i=1;i<=n;++i) vi[i]=oh[i];for (i=1;i<=hz;++i) getf(hu[i],i);for (i=1;i<=hz;++i) sm[i]=sm[i-1]+hv[i-1];build(1,1,hz);for (i=1;i<=hz;++i){if (i>1){j=i-1;k=(j==1 ? hz : j-1);sm[j]=sm[k]+hv[k];tch(1,1,hz,j);}ci=tr[1];if (ci.px!=ci.pn) ans=min(ans,ci.mx-ci.mn);else ans=min(ans,max(ci.mx-ci.cmn,ci.cmx-ci.mn));}printf("%.1f\n",1.*max(ans,ld)/2.); } View Code

?

轉載于:https://www.cnblogs.com/Rivendell/p/4760952.html

總結

以上是生活随笔為你收集整理的环套树的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 精品无码久久久久成人漫画 | 亚洲四虎影院 | 成人国产毛片 | 精品色综合 | www.av777| 蜜乳av一区二区三区 | 男女涩涩| 欧美成人一区在线 | 成年网站 | 精品一区二区久久久久蜜桃 | 国产又黄又猛的视频 | 91桃色免费视频 | 欧美偷拍亚洲 | aaa久久 | 美女久久久久久久久 | 日本欧美久久久久免费播放网 | 人人妻人人澡人人爽人人欧美一区 | 国产免费a视频 | av地址在线 | 自拍偷拍五月天 | 成年人看的网站 | 在线国产区 | 多毛的亚洲人毛茸茸 | 亚洲精品日日夜夜 | 一区二区三区在线看 | 午夜久久一区 | 无码久久av一区二区三区 | 日韩无套无码精品 | 99国产精品国产精品九九 | 日本久久精品视频 | www国产亚洲精品久久麻豆 | www.av网站| 国产精品一卡二卡在线观看 | 亚洲精品一区二区潘金莲 | 成人做爰www免费看视频网站 | 亚洲天堂第一页 | 国模精品视频一区二区 | 日韩中文字幕视频在线 | 久久噜噜噜精品国产亚洲综合 | 国产三级三级在线观看 | 国产精品午夜在线观看 | 青青草公开视频 | 国产成人精品999在线观看 | 久久久人 | 理论片在线观看理伦片 | 日本天堂免费a | 免费在线观看黄色 | 华人色| 国产又粗又长又硬免费视频 | 日本一区二区三区免费视频 | 黄色九九 | 一区二区精品视频 | 成年人免费大片 | 日韩不卡一二区 | 91大尺度| 一区二区三区四区精品视频 | av网站免费在线看 | 国产黄色在线观看 | 亚洲视频h| 欧美福利精品 | 日韩性xxxx| 成人av入口 | 亚洲无圣光 | 骚狐网站| xxsm.com| 一本色道久久综合亚洲精品酒店 | 精品视频无码一区二区三区 | 欧美日韩一区二区三区四区 | 亚洲影视一区二区 | 欧美黄色三级视频 | 人人妻人人藻人人爽欧美一区 | 国产一区成人 | 超碰成人久久 | 茄子视频懂你更多在线观看 | 影音先锋男人资源网站 | 91综合久久 | 欧美三级不卡 | 久久国语对白 | 五月婷婷导航 | 久久久久久久国产精品美女 | 末路1997全集免费观看完整版 | 国产日韩在线免费观看 | 少妇特黄a一区二区三区88av | 国产精品久久av无码一区二区 | 香蕉视频一级 | 国产一区导航 | 蜜桃视频在线入口www | 免费观看日本 | 手机看片久久久 | 亚洲制服丝袜av | 黑丝av在线 | 操操久久 | 欧美日韩激情视频 | 国产在线高清 | 女同性做爰全过程 | 国内外成人激情视频 | 国产一区91| 亚洲综合大片69999 | 97精品一区二区视频在线观看 |