bzoj 2238 Mst——树链剖分

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238

一条非树边可以对一条链的树边产生影响。注意是边,所以把边下放到点上,只要跳 top 时不赋 lca 就行。

然后WA*3。看看题解才知道有一开始图就不连通的情况!自己还是太嫩了……

只有单点查询很方便用标记永久化。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5e4+5,M=1e5+5;
int n,m,q,hd[N],xnt,to[N<<1],nxt[N<<1],fa[N],ans;
int tim,dfn[N],siz[N],dep[N],son[N],top[N];
int tot,ls[N<<1],rs[N<<1],mn[N<<1];
bool used[M],flag;
struct Ed{
  int x,y,w,bh;
  Ed(int a=0,int b=0,int c=0,int d=0):x(a),y(b),w(c),bh(d) {}
  bool operator< (const Ed &b)const
  {return w<b.w;}
}ed[M];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
bool cmp(Ed u,Ed v){return u.bh<v.bh;}
int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);}
void add(int x,int y)
{
  to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;
  to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;
}
void dfs(int cr)
{
  dep[cr]=dep[fa[cr]]+1; siz[cr]=1;
  for(int i=hd[cr],v;i;i=nxt[i])
    if((v=to[i])!=fa[cr])
      {
    fa[v]=cr; dfs(v); siz[cr]+=siz[v];
    siz[v]>siz[son[cr]]?son[cr]=v:0;
      }
}
void dfsx(int cr)
{
  dfn[cr]=++tim;
  if(son[cr])top[son[cr]]=top[cr],dfsx(son[cr]);
  for(int i=hd[cr],v;i;i=nxt[i])
    if((v=to[i])!=fa[cr]&&v!=son[cr])
      top[v]=v,dfsx(v);
}
void build(int l,int r,int cr)
{
  mn[cr]=M; if(l==r)return;
  int mid=l+r>>1;
  ls[cr]=++tot; build(l,mid,ls[cr]);
  rs[cr]=++tot; build(mid+1,r,rs[cr]);
}
void mdfy(int l,int r,int cr,int L,int R,int k)
{
  if(l>=L&&r<=R){mn[cr]=min(mn[cr],k);return;}
  int mid=l+r>>1;
  if(L<=mid)mdfy(l,mid,ls[cr],L,R,k);
  if(mid<R)mdfy(mid+1,r,rs[cr],L,R,k);
}
void mdfy(int x,int y,int w)
{
  while(top[x]!=top[y])
    {
      if(dep[top[x]]<dep[top[y]])swap(x,y);
      mdfy(1,n,1,dfn[top[x]],dfn[x],w);
      x=fa[top[x]];
    }
  if(x==y)return;//
  if(dep[x]<dep[y])swap(x,y);
  mdfy(1,n,1,dfn[son[y]],dfn[x],w);//son for no lca
}
int query(int l,int r,int cr,int p)
{
  if(l==r)return mn[cr];
  int mid=l+r>>1;
  if(p<=mid)return min(query(l,mid,ls[cr],p),mn[cr]);
  else return min(query(mid+1,r,rs[cr],p),mn[cr]);
}
int main()
{
  n=rdn();m=rdn();
  for(int i=1,u,v,z;i<=m;i++)
    {
      u=rdn(); v=rdn(); z=rdn();
      ed[i]=Ed(u,v,z,i);
    }
  for(int i=1;i<=n;i++)fa[i]=i;
  sort(ed+1,ed+m+1);
  for(int i=1,u,v;i<=m;i++)
    if((u=find(ed[i].x))!=(v=find(ed[i].y)))
      {
    used[ed[i].bh]=1; fa[u]=v;
    add(ed[i].x,ed[i].y); ans+=ed[i].w;
      }
  int d=find(1);
  for(int i=2;i<=n;i++)if(find(i)!=d){flag=1;break;}
  if(!flag)
    {
      sort(ed+1,ed+m+1,cmp);
      fa[1]=0; dfs(1); top[1]=1; dfsx(1); tot=1; build(1,n,1);
      for(int i=1;i<=m;i++)
    if(!used[i]) mdfy(ed[i].x,ed[i].y,ed[i].w);
    }
  q=rdn();
  for(int i=1,d;i<=q;i++)
    {
      d=rdn();
      if(flag){puts("Not connected");continue;}
      if(!used[d])printf("%d\n",ans);
      else
    {
      int k=query(1,n,1,max(dfn[ed[d].x],dfn[ed[d].y]));//ed[d]!
      if(k==M)puts("Not connected");
      else printf("%d\n",ans-ed[d].w+k);//ed[d]!
    }
    }
  return 0;
}

 

posted on 2018-10-17 08:50  Narh  阅读(210)  评论(0编辑  收藏  举报

导航