【[HEOI2014]大工程 】
阿新 • • 發佈:2019-01-01
for std line 在那 之間 cstring \n add iostream 的距離,如果\(x\)被標記了,那麽就在這次\(dfs\)之後把其變成\(0\),之後像直徑那樣合並就好了
可能是虛樹板子題了
首先先把虛樹建出來,但是這裏和那道虛樹的入門題不一樣,這裏所有的詢問點都得在虛樹裏,所以不會存在那種直接不如棧的點
之後我們考慮一下這個三個要求的東西
第一個操作我們需要統計虛樹上每一條邊的貢獻,即被多少個點對經過,根據乘法原理顯然有\((t-sz[x])\times sz[x]\times w\)的貢獻
第二個操作是最大的距離,這不就是直徑嗎,子樹內部最長鏈和次長鏈拼一下就好了
第三個操作是所有點對之間的最小值,因為虛樹上有一些點並不是被詢問的點,所以不能直接從虛樹上選擇最小的邊,還是需要\(dp\)一下
我們用\(g[x]\)表示\(x\)子樹內部的距離\(x\)最近的標記過得點到\(x\)
代碼
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define re register #define LL long long #define maxn 1000005 #define INF 99999999999 #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) inline int read() { re char c=getchar();int x=0; while(c<‘0‘||c>‘9‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } int n,m,num,__,t,top; LL ans,tot,cnt=INF; int head[maxn],head_[maxn],a[maxn],st[maxn]; int Top[maxn],fa[maxn],sum[maxn],deep[maxn],son[maxn],dfn[maxn]; LL sz[maxn],dp[maxn],f[maxn],to[maxn],g[maxn],to_[maxn]; struct E {int v,nxt;}e[maxn<<1]; struct Eg {int v,nxt,w;}e_[maxn<<1]; inline int cmp(int x,int y){return dfn[x]<dfn[y];} inline void add_edge(int x,int y){e[++num].v=y,e[num].nxt=head[x],head[x]=num;} inline void add(int x,int y,int z){e_[++num].v=y,e_[num].nxt=head_[x],e_[num].w=z,head_[x]=num;} void dfs1(int x) { sum[x]=1; int maxx=-1; for(re int i=head[x];i;i=e[i].nxt) if(!deep[e[i].v]) { deep[e[i].v]=deep[x]+1,fa[e[i].v]=x; dfs1(e[i].v); sum[x]+=sum[e[i].v]; if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v; } } void dfs2(int x,int topf) { Top[x]=topf,dfn[x]=++__; if(!son[x]) return; dfs2(son[x],topf); for(re int i=head[x];i;i=e[i].nxt) if(!Top[e[i].v]) dfs2(e[i].v,e[i].v); } inline int LCA(int x,int y) { while(Top[x]!=Top[y]){if(deep[Top[x]]<deep[Top[y]]) std::swap(x,y);x=fa[Top[x]];} if(deep[x]<deep[y]) return x;return y; } inline void ins(int x) { if(top==1){st[++top]=x;return;} int lca=LCA(x,st[top]); while(top>1&&dfn[st[top-1]]>=dfn[lca]) add(st[top-1],st[top],deep[st[top]]-deep[st[top-1]]),top--; if(lca!=st[top]) add(lca,st[top],deep[st[top]]-deep[lca]),st[top]=lca; st[++top]=x; } void Dfs(int x) { for(re int i=head_[x];i;i=e_[i].nxt) if(deep[e_[i].v]>deep[x]) { Dfs(e_[i].v); sz[x]+=sz[e_[i].v]; tot+=sz[e_[i].v]*((LL)t-sz[e_[i].v])*(LL)e_[i].w; if(dp[x]<dp[e_[i].v]+e_[i].w) dp[x]=dp[e_[i].v]+e_[i].w,to[x]=e_[i].v; if(g[x]>g[e_[i].v]+e_[i].w) g[x]=g[e_[i].v]+e_[i].w,to_[x]=e_[i].v; } ans=max(ans,dp[x]); if(f[x]) cnt=min(cnt,g[x]); for(re int i=head_[x];i;i=e_[i].nxt) if(deep[e_[i].v]>deep[x]&&to[x]!=e_[i].v) ans=max(ans,dp[x]+dp[e_[i].v]+(LL)e_[i].w); for(re int i=head_[x];i;i=e_[i].nxt) if(deep[e_[i].v]>deep[x]&&to_[x]!=e_[i].v) cnt=min(cnt,g[x]+g[e_[i].v]+(LL)e_[i].w); if(f[x]) g[x]=0; } void clear(int x) { sz[x]=0;dp[x]=0,to[x]=0;f[x]=0;g[x]=INF;to_[x]=0; for(re int i=head_[x];i;i=e_[i].nxt) if(deep[e_[i].v]>deep[x]) clear(e_[i].v); head_[x]=0; } int main() { n=read(); int x,y; for(re int i=1;i<n;i++) {x=read(),y=read();add_edge(x,y),add_edge(y,x);g[i]=INF;}g[n]=INF; deep[1]=1,dfs1(1),dfs2(1,1); m=read(); while(m--) { t=read();num=0;ans=0;tot=0;cnt=INF; for(re int i=1;i<=t;i++) a[i]=read(),sz[a[i]]++,f[a[i]]=1; std::sort(a+1,a+t+1,cmp);top=0; int root=LCA(a[1],a[2]); for(re int i=3;i<=t;i++) root=LCA(root,a[i]); st[++top]=root; for(re int i=1;i<=t;i++) if(root!=a[i]) ins(a[i]); while(top) add(st[top-1],st[top],deep[st[top]]-deep[st[top-1]]),top--; Dfs(root); printf("%lld %lld %lld\n",tot,cnt,ans); clear(root); } return 0; }
【[HEOI2014]大工程 】