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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

洛谷P2680:运输计划(倍增、二分、树上差分)

發(fā)布時(shí)間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷P2680:运输计划(倍增、二分、树上差分) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

傳送門(mén)

文章目錄

  • 題目描述
  • 解析
  • 問(wèn)題
  • 代碼

題目描述

解析

求最大值的最小值
容易想到二分
然后。。。就沒(méi)有然后了。。。
看了題解
學(xué)會(huì)了一個(gè)新技能:樹(shù)上差分
(其實(shí)學(xué)長(zhǎng)之前好像講過(guò)。。。)

一般的,對(duì)于一條A到B的路徑,如果要將其全部加上一個(gè)值w。我們可以把AB兩點(diǎn)的前綴加w,再把它們的lca及l(fā)ca的父親減去w,最后統(tǒng)計(jì)時(shí)用dfs統(tǒng)計(jì),每個(gè)點(diǎn)的價(jià)值就是其本身及子樹(shù)的前綴值之和
畫(huà)個(gè)圖就能很直觀的看出來(lái),請(qǐng)讀者自行動(dòng)筆探究~~(絕對(duì)不是我懶)~~
lca可以用許多算法優(yōu)化到log,這樣時(shí)間復(fù)雜度就很優(yōu)秀啦

本題對(duì)于一個(gè)二分出來(lái)的值mid,如果有一些路徑的長(zhǎng)度大于mid,那么刪的邊一定是這些不符合的路徑的公共邊(不然它還是不符合)
就相當(dāng)與每次把不符合的路徑上的點(diǎn)全部加1,再統(tǒng)計(jì)點(diǎn)權(quán)恰好等于不符合路徑個(gè)數(shù)的點(diǎn),它們之間的邊,就是可以刪的邊(這就能用差分啦)
其中選一條最大的,看減完它行不行即可

問(wèn)題

本題到這里思路就結(jié)束了
但真正做起來(lái)真的有點(diǎn)搬磚。。。
還遇到了很多細(xì)節(jié)問(wèn)題

1.樹(shù)上倍增的時(shí)候要注意單鏈時(shí)最后不用再跳一邊f(xié)ather了!
2.300000的log大于15(我掰手指頭當(dāng)成30000了。。。調(diào)了好久)
3.雙向邊要開(kāi)二倍!!!!

這都是經(jīng)常遇到的問(wèn)題,代碼復(fù)雜起來(lái)就又忘了,一定要引以為戒,注意細(xì)節(jié)!

代碼

#include<bits/stdc++.h> using namespace std; #define ll long long const int N=3e5+100; int n,m; struct node{int to,nxt,v; }p[2*N]; int fi[N],cnt=-1; void addline(int x,int y,int v){p[++cnt]=(node){y,fi[x],v};fi[x]=cnt; }int dep[N],fa[N],fv[N]; void dfs(int x,int f){for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;fa[to]=x;dep[to]=dep[x]+1;fv[to]=p[i].v;dfs(to,x);}return; } int pl[22][N],dis[22][N],mi[22]; void solve(){mi[0]=1;for(int i=1;i<=20;i++) mi[i]=mi[i-1]*2;for(int i=2;i<=n;i++){pl[0][i]=fa[i];dis[0][i]=fv[i];}for(int k=1;k<=20;k++){for(int i=1;i<=n;i++){if(dep[i]<mi[k]) continue;pl[k][i]=pl[k-1][pl[k-1][i]];dis[k][i]=dis[k-1][i]+dis[k-1][pl[k-1][i]];}}return; } int place,tot; void find(int x,int y){tot=0;if(dep[x]<dep[y]) swap(x,y);for(int k=20;k>=0;k--){if(dep[x]-mi[k]>=dep[y]){tot+=dis[k][x];x=pl[k][x];}}for(int k=20;k>=0;k--){if(dep[x]<mi[k]||pl[k][x]==pl[k][y]) continue;tot+=dis[k][x];x=pl[k][x];tot+=dis[k][y];y=pl[k][y]; // printf("x=%d y=%d tot=%d\n",x,y,tot);}place=x;if(x!=y){tot+=fv[x];tot+=fv[y];place=fa[place];} }struct node2{int x,y,len,lca; }q[N]; int a,b,c;int num; int pre[N],sum[N]; void dfs2(int x,int f,int &ans){sum[x]=pre[x];for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs2(to,x,ans);sum[x]+=sum[to];}if(sum[x]!=num) return;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(sum[to]==num){ans=max(ans,p[i].v); // printf("x=%d y=%d v=%d\n",x,to,fv[to]);}}return; } bool check(int mid){int mx=0;num=0;memset(pre,0,sizeof(pre));memset(sum,0,sizeof(sum)); // printf("check: (%d)\n",mid);for(int i=1;i<=m;i++){if(q[i].len>mid){num++;mx=max(mx,q[i].len);pre[q[i].x]++;pre[q[i].y]++;pre[q[i].lca]--;pre[fa[q[i].lca]]--;}}if(num==0) return true;int ans=0;dfs2(1,0,ans); // printf(" num=%d ans=%d\n",num,ans);if(mx-ans<=mid) return true;else return false; } int main(){memset(fi,-1,sizeof(fi)); // printf("%d",sizeof(pl)/1024/1024);scanf("%d%d",&n,&m);for(int i=1;i<n;i++){scanf("%d%d%d",&a,&b,&c);addline(a,b,c);addline(b,a,c);}dfs(1,0);solve(); // for(int i=1;i<=n;i++) printf("i=%d fa=%d dep=%d\n",i,fa[i],dep[i]);for(int i=1;i<=m;i++){scanf("%d%d",&a,&b);find(a,b);q[i]=(node2){a,b,tot,place}; // printf("tot=%d pl=%d\n",tot,place);}int st=0,ed=2e9;while(st<ed){ // printf("st=%d ed=%d\n",st,ed);int mid=(st+ed)>>1;if(check(mid)) ed=mid;else st=mid+1;}printf("%d",st); } /* 12 3 1 2 8 1 3 1 1 4 8 2 5 6 2 7 5 2 6 4 6 8 7 6 9 5 3 10 6 3 12 3 10 11 5 1 11 3 11 10 116 4 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5 2 4 */

總結(jié)

以上是生活随笔為你收集整理的洛谷P2680:运输计划(倍增、二分、树上差分)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。