[Luogu P5680][GZOI2017]共享单车
之前没看懂题意就把这题扔了,现在一看是读错题意了
简化版题意
给出一颗树(这个图的最短路径生成树),每个点初始颜色为\(0\)
两种操作:
将部分点颜色取反
给出一些点,建出虚树(边权为两点树上距离),求最小割边代价使得虚树上没有颜色为\(1\)的点与根联通
那这就很模板了:
设\(f[x]\)表示\(x\)子树的答案,\(c[x]\)表示\(x\)的颜色,则有转移方程:(当\(f[K]=0\)时输出\(-1\))
\[f[x]+=Val(x,y)\quad (c[y]=1)\\
f[x]+=\min (Val(x,y),f[y])\quad (c[y]=0)
\]
(注意以上方法没有考虑边权全为\(0\)但是答案不为\(-1\)的情况,不过好像没有这种数据,反正也不难特判就没管了)
时间复杂度 \(O((N+M)\log N+Qnum(\log num+\log N))\)
(数据为什么这么小)
代码:
#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
inline char Getchar()
{
static char In[1<<22],*p1=In,*p2=In;
return p1==p2&&(p2=(p1=In)+fread(In,1,1<<22,stdin),p1==p2)?EOF:*p1++;
}
inline int Getint()
{
int x=0,c;
while(!isdigit(c=Getchar()));
for(;isdigit(c);c=Getchar())x=x*10+(c^48);
return x;
}
const int N=50005,Inf=0x7f7f7f7f;
int n,M,K,Q,Dis[N],Pre[N];
int Dfn[N],Tim,Dep[N],f[N][16];
int c[N],a[N],s[N],Top;
std::vector<int> G[N],Gv[N],T[N],V[N];
//Graph|Graph Value|Tree|Virtual Tree
void Dijkstra()
{
struct Rec{int x,d;inline bool operator<(const Rec& o)const{return d>o.d;}};
std::priority_queue<Rec> q;
memset(Dis,0x7f,sizeof Dis);
q.push((Rec){K,Dis[K]=0});
while(!q.empty())
{
int x=q.top().x,d=q.top().d;
if(q.pop(),d!=Dis[x])continue;
for(int i=0,y,v;i<(int)G[x].size();++i)
if(Dis[y=G[x][i]]>Dis[x]+(v=Gv[x][i])||(Dis[y]==Dis[x]+v&&x<Pre[y]))
q.push((Rec){y,Dis[y]=Dis[x]+v}),Pre[y]=x;
}
for(int i=1;i<=n;++i)if(i!=K)T[Pre[i]].push_back(i);
}
void DFS(int x,int Fa)
{
Dfn[x]=++Tim,Dep[x]=Dep[f[x][0]=Fa]+1;
for(int i=1;i<=15;++i)f[x][i]=f[f[x][i-1]][i-1];
for(auto y:T[x])if(y!=Fa)DFS(y,x);
}
int Lca(int x,int y)
{
if(Dep[x]<Dep[y])std::swap(x,y);
for(int i=15;i>=0;--i)if(Dep[f[x][i]]>=Dep[y])x=f[x][i];
if(x==y)return y;
for(int i=15;i>=0;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[y][0];
}
int DP(int x)
{
int Res=0;
for(auto y:V[x])
{
int v=DP(y);
if(c[y])Res+=Dis[y]-Dis[x];
else Res+=std::min(v,Dis[y]-Dis[x]);
}
V[x].clear();
return Res;
}
int main()
{
//freopen("in.txt","r",stdin);
n=Getint(),M=Getint(),K=Getint(),Q=Getint();
for(int i=1,x,y,z;i<=M;++i)
{
x=Getint(),y=Getint(),z=Getint();
G[x].push_back(y),Gv[x].push_back(z);
G[y].push_back(x),Gv[y].push_back(z);
}
Dijkstra(),DFS(K,0);
for(int o,k;Q--;)
if(o=Getint(),k=Getint(),!o)while(k--)c[Getint()]^=1;
else
{
for(int i=1;i<=k;++i)a[i]=Getint();
s[Top=1]=K,std::sort(a+1,a+k+1,[](int x,int y){return Dfn[x]<Dfn[y];});
for(int i=1;i<=k;++i)
{
int Ls=Lca(s[Top],a[i]);
while(Top>1&&Dfn[s[Top-1]]>=Dfn[Ls])V[s[Top-1]].push_back(s[Top]),--Top;
if(s[Top]!=Ls)V[Ls].push_back(s[Top]),s[Top]=Ls;
s[++Top]=a[i];
}
while(Top>1)V[s[Top-1]].push_back(s[Top]),--Top;
int Ans=DP(K);
printf("%d\n",Ans?Ans:-1);
}
return 0;
}