uoj#87. mx的仙人掌 //圆方树或者别的什么东西

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;
    }
}

猜你喜欢

转载自blog.csdn.net/Starria/article/details/79149680