BZOJ 2238: Mst DFS序+KDtree
明明可以用二维数点来做啊,网上为什么都是树剖+线段树呢 ?
code:
#include <cstdio> #include <cstring> #include <algorithm> #define N 100006 #define inf 1000000 #define ll long long #define IO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; namespace KD { int d; struct node { int ch[2],p[2],mn[2],mx[2],Min,val; }t[N]; bool cmp(node a,node b) { return a.p[d]==b.p[d]?a.p[d^1]<b.p[d^1]:a.p[d]<b.p[d]; } int isin(int x1,int y1,int x2,int y2,int x) { if(t[x].mn[0]>=x1&&t[x].mx[0]<=y1&&t[x].mn[1]>=x2&&t[x].mx[1]<=y2) return 1; return 0; } int isout(int x1,int y1,int x2,int y2,int x) { if(x1>t[x].mx[0]||y1<t[x].mn[0]||x2>t[x].mx[1]||y2<t[x].mn[1]) return 1; return 0; } void pushup(int x,int y) { for(int i=0;i<2;++i) { t[x].mn[i]=min(t[x].mn[i],t[y].mn[i]); t[x].mx[i]=max(t[x].mx[i],t[y].mx[i]); } t[x].Min=min(t[x].Min,t[y].Min); } int build(int l,int r,int o) { d=o; int mid=(l+r)>>1; nth_element(t+l,t+mid,t+1+r,cmp); t[mid].mn[0]=t[mid].mx[0]=t[mid].p[0]; t[mid].mn[1]=t[mid].mx[1]=t[mid].p[1]; t[mid].Min=t[mid].val; if(mid>l) { t[mid].ch[0]=build(l,mid-1,o^1); pushup(mid,t[mid].ch[0]); } if(r>mid) { t[mid].ch[1]=build(mid+1,r,o^1); pushup(mid,t[mid].ch[1]); } return mid; } int query(int x1,int y1,int x2,int y2,int x) { if(isout(x1,y1,x2,y2,x)) return inf; if(isin(x1,y1,x2,y2,x)) return t[x].Min; int re=inf; if(t[x].p[0]>=x1&&t[x].p[0]<=y1&&t[x].p[1]>=x2&&t[x].p[1]<=y2) { re=min(re,t[x].val); } if(t[x].ch[0]) re=min(re,query(x1,y1,x2,y2,t[x].ch[0])); if(t[x].ch[1]) re=min(re,query(x1,y1,x2,y2,t[x].ch[1])); return re; } }; namespace T { int p[N]; void init(int x) { for(int i=1;i<=x;++i) p[i]=i; } int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } int merge(int x,int y) { x=find(x),y=find(y); if(x!=y) { p[x]=y; return 1; } else return 0; } }; struct Edge { int x,y,c,id; Edge(int x=0,int y=0,int c=0,int id=0):x(x),y(y),c(c),id(id){} bool operator<(Edge a) const { return c<a.c; } }e[N]; int n,m,edges,dfn; int hd[N],to[N<<1],nex[N<<1],val[N<<1],mk[N],fa[N],st[N],ed[N],go[N]; void add(int u,int v,int c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } void dfs(int u,int ff) { fa[u]=ff; st[u]=++dfn; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(v==ff) continue; dfs(v,u); } ed[u]=dfn; } int main() { // IO("input"); int i,j; scanf("%d%d",&n,&m); for(i=1;i<=m;++i) { int x,y,z; scanf("%d%d%d",&x,&y,&z); e[i]=Edge(x,y,z,i); } sort(e+1,e+1+m); T::init(n); ll ans=0; int cn=0,tot=0; for(i=1;i<=m;++i) { if(T::merge(e[i].x,e[i].y)) { ans+=(ll)e[i].c; mk[e[i].id]=1,++cn; add(e[i].x,e[i].y,e[i].c); add(e[i].y,e[i].x,e[i].c); } } if(cn==n-1) dfs(1,0); for(i=1;i<=m;++i) { go[e[i].id]=i; if(!mk[e[i].id]) { int x=e[i].x; int y=e[i].y; if(st[x]>st[y]) swap(x,y); ++tot; KD::t[tot].val=e[i].c; KD::t[tot].p[0]=st[x]; KD::t[tot].p[1]=st[y]; } } int root=KD::build(1,tot,0); int q; scanf("%d",&q); for(i=1;i<=q;++i) { int cur; scanf("%d",&cur); if(cn<n-1) printf("Not connected\n"); else { if(!mk[cur]) printf("%lld\n",ans); else { cur=go[cur]; int x=e[cur].x; int y=e[cur].y; if(fa[y]==x) swap(x,y); int re=inf; if(st[x]>1) { re=min(re,KD::query(1,st[x]-1,st[x],ed[x],root)); } if(ed[x]<n) { re=min(re,KD::query(st[x],ed[x],ed[x]+1,n,root)); } if(re==inf) printf("Not connected\n"); else printf("%lld\n",ans-e[cur].c+re); } } } return 0; }