题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=1969
题解:
线段树,树链剖分,反向考虑
思路是很巧妙,但是感觉代码真的恶心。。
反着考虑,先按照给出的操作把所有该删的边都删掉,
那么剩下的也还是一个联通块。(题目保证了的)
然后在该联通块里随便选出某些边来形成一颗树。
那么显然,若只看树边的话,每一条树边都是一条关键边,
如果此时加一条其他的边 e(x,y),使得形成了一个环,
那么显然 x ~ y 路径上的边都不再是关键边。
那么此时问题变为了树上的区间覆盖问题,树链剖分+线段树来解决就好了。
(另外,会用到 hash或者 map的)
代码:(三份,分别是用到map,hash和hash表的,hahaha)
map
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 40500 #define MAXM 100500 using namespace std; int fa[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],pos[MAXN],ord[MAXN],ANS[MAXN]; int N,M,snt,ont,ant; typedef pair<int,int>pii; map<pii,bool>H; struct Oper{ int type,x,y; }stk[MAXN]; struct Edge{ int to[MAXM*2],nxt[MAXM*2],mark[MAXM*2],head[MAXN],ent; Edge(){ ent=2; memset(head,0,sizeof(head)); } void Adde(int u,int v){ to[ent]=v; nxt[ent]=head[u]; head[u]=ent++; to[ent]=u; nxt[ent]=head[v]; head[v]=ent++; } }E; struct SGT{ int ls[MAXN*2],rs[MAXN*2],rem[MAXN*2],sz,rt; void pushup(int u){ rem[u]=rem[ls[u]]+rem[rs[u]]; } void Build(int &u,int l,int r){ u=++sz; if(l==r){rem[u]=1; return;} int mid=(l+r)>>1; Build(ls[u],l,mid); Build(rs[u],mid+1,r); pushup(u); } void Modify(int u,int l,int r,int al,int ar){ if(!rem[u]) return; if(al<=l&&r<=ar){rem[u]=0; return;} int mid=(l+r)>>1; if(al<=mid) Modify(ls[u],l,mid,al,ar); if(mid<ar) Modify(rs[u],mid+1,r,al,ar); pushup(u); } int Query(int u,int l,int r,int al,int ar){ if(!rem[u]) return 0; if(al<=l&&r<=ar) return rem[u]; int mid=(l+r)>>1,ret=0; if(al<=mid) ret+=Query(ls[u],l,mid,al,ar); if(mid<ar) ret+=Query(rs[u],mid+1,r,al,ar); return ret; } }DT; void read(int &x){ static int f; static char ch; x=0; f=1; ch=getchar(); while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x=x*f; } int dfs1(int u,int dad){ static bool vis[MAXN]; int bgn=0,num=1,son; vis[u]=1; fa[u]=dad; for(int i=E.head[u],v;i;i=E.nxt[i]){ v=E.to[i]; if(vis[v]) continue; if(H[make_pair(u,v)]) continue; E.mark[i]=1; E.mark[i^1]=1; son=dfs1(v,u); if(bgn<son) bgn=son,bgs[u]=v; num+=son; } return num; } void dfs2(int u,int tp){ ord[++ont]=u; pos[u]=ont; top[u]=tp; dep[u]=dep[fa[u]]+1; if(bgs[u]) dfs2(bgs[u],tp); for(int i=E.head[u],v;i;i=E.nxt[i]) if(E.mark[i]){ v=E.to[i]; if(v==bgs[u]||v==fa[u]) continue; dfs2(v,v); } } void cover(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]]) swap(u,v); DT.Modify(DT.rt,1,N,pos[top[v]],pos[v]); v=fa[top[v]]; } if(u==v) return; if(dep[u]>dep[v]) swap(u,v); DT.Modify(DT.rt,1,N,pos[u]+1,pos[v]); } int answer(int u,int v){ int ret=0; while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]]) swap(u,v); ret+=DT.Query(DT.rt,1,N,pos[top[v]],pos[v]); v=fa[top[v]]; } if(u==v) return ret; if(dep[u]>dep[v]) swap(u,v); ret+=DT.Query(DT.rt,1,N,pos[u]+1,pos[v]); return ret; } int main(){ //freopen("1969.out","w",stdout); read(N); read(M); for(int i=1,u,v;i<=M;i++) read(u),read(v),E.Adde(u,v); while(1){ read(stk[snt+1].type); if(stk[snt+1].type==-1) break; snt++; read(stk[snt].x); read(stk[snt].y); if(stk[snt].type) continue; H[make_pair(stk[snt].x,stk[snt].y)]=1; H[make_pair(stk[snt].y,stk[snt].x)]=1; } dfs1(1,0); dfs2(1,1); DT.Build(DT.rt,1,N); for(int u=1,v;u<=N;u++) for(int i=E.head[u];i;i=E.nxt[i]){ v=E.to[i]; if(u>v||E.mark[i]) continue; if(H[make_pair(u,v)]) continue; cover(u,v); } while(snt){ if(stk[snt].type) ANS[++ant]=answer(stk[snt].x,stk[snt].y); else cover(stk[snt].x,stk[snt].y); snt--; } while(ant) printf("%d ",ANS[ant--]); return 0; }
hash
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 40500 #define MAXM 100500 using namespace std; int fa[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],pos[MAXN],ord[MAXN],ANS[MAXN]; int N,M,snt,ont,ant; struct Oper{ int type,x,y; }stk[MAXN]; struct Edge{ int to[MAXM*2],nxt[MAXM*2],mark[MAXM*2],head[MAXN],ent; Edge(){ ent=2; memset(head,0,sizeof(head)); } void Adde(int u,int v){ to[ent]=v; nxt[ent]=head[u]; head[u]=ent++; to[ent]=u; nxt[ent]=head[v]; head[v]=ent++; } }E; struct Hash{ long long C[MAXN];int cnt; void Push(int a,int b){ if(a>b) swap(a,b); C[++cnt]=(1ll*a<<30)+b; } void Finish(){ sort(C+1,C+cnt+1); } bool Exist(int a,int b){ static int p; static long long w; if(a>b) swap(a,b); w=(1ll*a<<30)+b; p=lower_bound(C+1,C+cnt+1,w)-C; return C[p]==w; } }H; struct SGT{ int ls[MAXN*2],rs[MAXN*2],rem[MAXN*2],sz,rt; void pushup(int u){ rem[u]=rem[ls[u]]+rem[rs[u]]; } void Build(int &u,int l,int r){ u=++sz; if(l==r){rem[u]=1; return;} int mid=(l+r)>>1; Build(ls[u],l,mid); Build(rs[u],mid+1,r); pushup(u); } void Modify(int u,int l,int r,int al,int ar){ if(!rem[u]) return; if(al<=l&&r<=ar){rem[u]=0; return;} int mid=(l+r)>>1; if(al<=mid) Modify(ls[u],l,mid,al,ar); if(mid<ar) Modify(rs[u],mid+1,r,al,ar); pushup(u); } int Query(int u,int l,int r,int al,int ar){ if(!rem[u]) return 0; if(al<=l&&r<=ar) return rem[u]; int mid=(l+r)>>1,ret=0; if(al<=mid) ret+=Query(ls[u],l,mid,al,ar); if(mid<ar) ret+=Query(rs[u],mid+1,r,al,ar); return ret; } }DT; void read(int &x){ static int f; static char ch; x=0; f=1; ch=getchar(); while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x=x*f; } int dfs1(int u,int dad){ static bool vis[MAXN]; int bgn=0,num=1,son; vis[u]=1; fa[u]=dad; for(int i=E.head[u],v;i;i=E.nxt[i]){ v=E.to[i]; if(vis[v]) continue; if(H.Exist(u,v)) continue; E.mark[i]=1; E.mark[i^1]=1; son=dfs1(v,u); if(bgn<son) bgn=son,bgs[u]=v; num+=son; } return num; } void dfs2(int u,int tp){ ord[++ont]=u; pos[u]=ont; top[u]=tp; dep[u]=dep[fa[u]]+1; if(bgs[u]) dfs2(bgs[u],tp); for(int i=E.head[u],v;i;i=E.nxt[i]) if(E.mark[i]){ v=E.to[i]; if(v==bgs[u]||v==fa[u]) continue; dfs2(v,v); } } void cover(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]]) swap(u,v); DT.Modify(DT.rt,1,N,pos[top[v]],pos[v]); v=fa[top[v]]; } if(u==v) return; if(dep[u]>dep[v]) swap(u,v); DT.Modify(DT.rt,1,N,pos[u]+1,pos[v]); } int answer(int u,int v){ int ret=0; while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]]) swap(u,v); ret+=DT.Query(DT.rt,1,N,pos[top[v]],pos[v]); v=fa[top[v]]; } if(u==v) return ret; if(dep[u]>dep[v]) swap(u,v); ret+=DT.Query(DT.rt,1,N,pos[u]+1,pos[v]); return ret; } int main(){ //freopen("1969.out","w",stdout); read(N); read(M); for(int i=1,u,v;i<=M;i++) read(u),read(v),E.Adde(u,v); while(1){ read(stk[snt+1].type); if(stk[snt+1].type==-1) break; snt++; read(stk[snt].x); read(stk[snt].y); if(stk[snt].type) continue; H.Push(stk[snt].x,stk[snt].y); } H.Finish(); dfs1(1,0); dfs2(1,1); DT.Build(DT.rt,1,N); for(int u=1,v;u<=N;u++) for(int i=E.head[u];i;i=E.nxt[i]){ v=E.to[i]; if(u>v||E.mark[i]) continue; if(H.Exist(u,v)) continue; cover(u,v); } while(snt){ if(stk[snt].type) ANS[++ant]=answer(stk[snt].x,stk[snt].y); else cover(stk[snt].x,stk[snt].y); snt--; } while(ant) printf("%d ",ANS[ant--]); return 0; }
hash表(第一次写哈希表)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 40500 #define MAXM 100500 using namespace std; int fa[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],pos[MAXN],ord[MAXN],ANS[MAXN]; int N,M,snt,ont,ant; struct Oper{ int type,x,y; }stk[MAXN]; struct Edge{ int to[MAXM*2],nxt[MAXM*2],mark[MAXM*2],head[MAXN],ent; Edge(){ent=2;} void Adde(int u,int v){ to[ent]=v; nxt[ent]=head[u]; head[u]=ent++; to[ent]=u; nxt[ent]=head[v]; head[v]=ent++; } }E; struct Hash{ int to1[MAXN],to2[MAXN],nxt[MAXN],head[50000],ent,BIT,MOD; Hash(){BIT=12356789; MOD=43517; ent=2;} void Push(int a,int b){ static int u; if(a>b) swap(a,b); u=(1ll*a*BIT+b)%MOD; to1[ent]=a; to2[ent]=b; nxt[ent]=head[u]; head[u]=ent++; } bool Exist(int a,int b){ static int u; if(a>b) swap(a,b); u=(1ll*a*BIT+b)%MOD; for(int i=head[u];i;i=nxt[i]) if(to1[i]==a&&to2[i]==b) return 1; return 0; } }H; struct SGT{ int ls[MAXN*2],rs[MAXN*2],rem[MAXN*2],sz,rt; void pushup(int u){ rem[u]=rem[ls[u]]+rem[rs[u]]; } void Build(int &u,int l,int r){ u=++sz; if(l==r){rem[u]=1; return;} int mid=(l+r)>>1; Build(ls[u],l,mid); Build(rs[u],mid+1,r); pushup(u); } void Modify(int u,int l,int r,int al,int ar){ if(!rem[u]) return; if(al<=l&&r<=ar){rem[u]=0; return;} int mid=(l+r)>>1; if(al<=mid) Modify(ls[u],l,mid,al,ar); if(mid<ar) Modify(rs[u],mid+1,r,al,ar); pushup(u); } int Query(int u,int l,int r,int al,int ar){ if(!rem[u]) return 0; if(al<=l&&r<=ar) return rem[u]; int mid=(l+r)>>1,ret=0; if(al<=mid) ret+=Query(ls[u],l,mid,al,ar); if(mid<ar) ret+=Query(rs[u],mid+1,r,al,ar); return ret; } }DT; void read(int &x){ static int f; static char ch; x=0; f=1; ch=getchar(); while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x=x*f; } int dfs1(int u,int dad){ static bool vis[MAXN]; int bgn=0,num=1,son; vis[u]=1; fa[u]=dad; for(int i=E.head[u],v;i;i=E.nxt[i]){ v=E.to[i]; if(vis[v]) continue; if(H.Exist(u,v)) continue; E.mark[i]=1; E.mark[i^1]=1; son=dfs1(v,u); if(bgn<son) bgn=son,bgs[u]=v; num+=son; } return num; } void dfs2(int u,int tp){ ord[++ont]=u; pos[u]=ont; top[u]=tp; dep[u]=dep[fa[u]]+1; if(bgs[u]) dfs2(bgs[u],tp); for(int i=E.head[u],v;i;i=E.nxt[i]) if(E.mark[i]){ v=E.to[i]; if(v==bgs[u]||v==fa[u]) continue; dfs2(v,v); } } void cover(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]]) swap(u,v); DT.Modify(DT.rt,1,N,pos[top[v]],pos[v]); v=fa[top[v]]; } if(u==v) return; if(dep[u]>dep[v]) swap(u,v); DT.Modify(DT.rt,1,N,pos[u]+1,pos[v]); } int answer(int u,int v){ int ret=0; while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]]) swap(u,v); ret+=DT.Query(DT.rt,1,N,pos[top[v]],pos[v]); v=fa[top[v]]; } if(u==v) return ret; if(dep[u]>dep[v]) swap(u,v); ret+=DT.Query(DT.rt,1,N,pos[u]+1,pos[v]); return ret; } int main(){ //freopen("1969.out","w",stdout); read(N); read(M); for(int i=1,u,v;i<=M;i++) read(u),read(v),E.Adde(u,v); while(1){ read(stk[snt+1].type); if(stk[snt+1].type==-1) break; snt++; read(stk[snt].x); read(stk[snt].y); if(stk[snt].type) continue; H.Push(stk[snt].x,stk[snt].y); } dfs1(1,0); dfs2(1,1); DT.Build(DT.rt,1,N); for(int u=1,v;u<=N;u++) for(int i=E.head[u];i;i=E.nxt[i]){ v=E.to[i]; if(u>v||E.mark[i]) continue; if(H.Exist(u,v)) continue; cover(u,v); } while(snt){ if(stk[snt].type) ANS[++ant]=answer(stk[snt].x,stk[snt].y); else cover(stk[snt].x,stk[snt].y); snt--; } while(ant) printf("%d ",ANS[ant--]); return 0; }