uoj#87. mx的仙人掌
题意
给出一个N(<=3e5)个点的仙人掌,Q次询问,每次询问给定k(∑k<=3e5)个点,求k个点中两点间最短路的最大值。
题解
既然有官方题解那么就不写题解了。
看起来有好多可怕的做法…
当作圆方树的模板题写了一发,对圆方树建虚树什么的很妙的样子
注意事项
邻接表要开到n*4…怎么就记不住呢
昨天刚写错一次 然后今天又开小了
代码
放个代码证明今天没有在颓废。
写起来感觉不是很顺手;_;大概是同类题写得少的缘故
#include<bits/stdc++.h>
#define N 600005
#define L 20
using namespace std;
typedef long long ll;
char ch;
inline void rd(int &x)
{
x=0;
do ch=getchar();
while(ch<'0'||ch>'9');
do x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
while(ch>='0'&&ch<='9');
}
ll ss[N],dep[N],mx[N],Len[N],tmp,ans;
int n,m,Q,now,qt,h,t,tot,f[N][L],
dfn[N],low[N],no[N],st[N],q[N],dp[N],
To[N],Hd[N],Lk[N],Cnt,
to[N<<1],hd[N<<1],lk[N],len[N<<1],cnt=1;
inline ll D(int x,int y,int fr)
{
if(no[x]<no[y])return ss[y]-ss[x];
return ss[fr]-ss[x]+ss[y];
}
inline ll dis(int x,int y,int fr)
{
ll r1=D(x,y,fr),r2=D(y,x,fr);
return r1<r2?r1:r2;
}
inline void Add(int u,int v,ll w)
{To[++Cnt]=v,Hd[Cnt]=Lk[u],Len[Cnt]=w,Lk[u]=Cnt;}
inline void skip(int &x,int d)
{
for(int i=0;i<L&&d;i++)
if(d>>i&1)
d^=(1<<i),x=f[x][i];
}
inline void add(int u,int v,int w)
{
if(u>n)
{
w=v;skip(w,dp[v]-dp[u]-1);
to[++cnt]=w,hd[cnt]=lk[u],lk[u]=cnt;
if(w^v)add(w,v,0);
}
else
to[++cnt]=v,hd[cnt]=lk[u],len[cnt]=w,lk[u]=cnt;
}
void dfs(int x,int fr)
{
dfn[x]=low[x]=++now;
for(int s,i=lk[x];i;i=hd[i])
if(i^fr)
{
if(!dfn[s=to[i]])
{
st[t++]=i,dfs(s,i^1);
low[x]=low[low[x]<low[s]?x:s];
if(low[s]>=dfn[x])
{
if(st[--t]==i)
{Add(x,s,len[i]);continue;}
qt=tmp=0;Add(x,++tot,0);
do
{
ss[q[no[to[st[t]]]=qt++]=to[st[t]]]=tmp,
tmp+=len[st[t]];
}while(st[t--]^i);
t++;ss[tot]=tmp;
for(int j=1;j<qt;j++)
Add(tot,q[j],dis(q[j],x,tot));
}
}
else
{
low[x]=low[x]<dfn[s]?low[x]:dfn[s];
if(dfn[s]<dfn[x])st[t++]=i;
}
}
}
void ini(int x)
{
dfn[x]=++now,dp[x]=dp[f[x][0]]+1;
for(int i=1;i<L&&f[x][i-1];i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int s,i=Lk[x];i;i=Hd[i])
f[s=To[i]][0]=x,dep[s]=dep[x]+Len[i],ini(s);
}
void dfss(int x)
{
mx[x]=0;
for(int s,i=lk[x];i;i=hd[i])
{
dfss(s=to[i]);tmp=mx[s]+dep[s]-dep[x];
if(x<=n)
ans=ans<mx[x]+tmp?mx[x]+tmp:ans;
mx[x]=mx[x]<tmp?tmp:mx[x];
}
if(x>n)
{
qt=h=t=0;
for(int i=lk[x];i;i=hd[i])
st[qt++]=to[i];
for(int i=0,j=1;i<qt;i++)
{
if(h<t&&q[h]==st[i])h++;
if(j==i){j++;if(j==qt)j=0;}
while(j^i)
{
ll r1=D(st[i],st[j],x),r2=D(st[j],st[i],x);
if(r1>r2)break;
while(h<t&&dis(st[i],st[j],x)+mx[st[j]]>=
dis(q[t-1],st[i],x)+mx[q[t-1]])t--;
q[t++]=st[j];
j++;if(j==qt)j=0;
}
if(h<t)ans=ans<mx[q[h]]+dis(q[h],st[i],x)+mx[st[i]]?
mx[q[h]]+dis(q[h],st[i],x)+mx[st[i]]:ans;
}
}
lk[x]=0;
}
int u,v,w,k,a[N];
bool cmp(int x,int y)
{return dfn[x]<dfn[y];}
int main()
{
rd(n),rd(m),tot=n;
while(m--)
rd(u),rd(v),rd(w),
add(u,v,w),add(v,u,w);
dfs(1,0);ini(1);
for(int i=1;i<=tot;i++)
lk[i]=0;
cnt=0;rd(Q);
while(Q--)
{
rd(k);
for(int i=0;i<k;i++)
rd(a[i]);
sort(a,a+k,cmp);t=0;
for(int i=0;i<k;i++)
if(t)
{
u=a[i],v=st[t-1];
if(dp[u]<dp[v])swap(u,v);
skip(u,dp[u]-dp[v]);
for(int j=L-1;j>=0;j--)
if(f[u][j]^f[v][j])
u=f[u][j],v=f[v][j];
if(u^v)u=f[u][0];
qt=0;
while(t&&dp[st[t-1]]>=dp[u])
{
v=st[--t];
if(qt)add(v,qt,0);
qt=v;
}
if(u^qt)add(u,qt,0);
st[t++]=u;
if(u^a[i])st[t++]=a[i];
}
else st[t++]=a[i];
while(--t)
add(st[t-1],st[t],0);
dfss(st[0]);
printf("%lld\n",ans);
cnt=t=ans=0;
}
}