题链:

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\n",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\n",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\n",ANS[ant--]);
return 0;
}

●BZOJ 1969 [Ahoi2005]LANE 航线规划的更多相关文章

  1. BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )

    首先我们要时光倒流, 倒着做, 变成加边操作维护关键边. 先随意搞出一颗树, 树上每条边都是关键边(因为是树, 去掉就不连通了)....然后加边(u, v)时, 路径(u, v)上的所有边都变成非关键 ...

  2. 【刷题】BZOJ 1969 [Ahoi2005]LANE 航线规划

    Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel ...

  3. BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]

    题意: 一张图,删除边,求两点之间的割边数量.保证任意时刻图连通 任求一棵生成树,只有树边可能是割边 时间倒流,加入一条边,就是两点路径上的边都不可能是割边,区间覆盖... 然后本题需要把边哈希一下, ...

  4. 【BZOJ 1969】 1969: [Ahoi2005]LANE 航线规划 (树链剖分+线段树)

    1969: [Ahoi2005]LANE 航线规划 Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星 ...

  5. 【BZOJ】1969: [Ahoi2005]LANE 航线规划

    题目链接: 传送~~ 题解:  老夫实在是码不动了…… 正着搞显然不好做,尝试倒着乱搞.先给被删除的边标记一个时间戳,先删除的时间戳大,同时维护询问时间戳,询问早的时间戳大.没被删除过的边时间戳都是0 ...

  6. 【BZOJ1969】[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树

    [BZOJ1969][Ahoi2005]LANE 航线规划 Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由 ...

  7. [Ahoi2005]LANE 航线规划

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  8. BZOJ1969: [Ahoi2005]LANE 航线规划(LCT)

    Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 587  Solved: 259[Submit][Status][Discuss] Description ...

  9. 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

随机推荐

  1. Alpha集合

    项目名称:城市安全风险管控系统 小组成员: 张梨贤.林静.周静平.黄腾飞 Alpha冲刺随笔 Alpha冲刺Day1 Alpha冲刺Day2 Alpha冲刺Day3 Alpha冲刺Day4 Alpha ...

  2. APP的案例分析-美团外卖

    大一才开始用软件订外卖了,很方便  ,上手快只要注册个账号登陆即可,支付时自动跳转到其他支付应用.严重的bug也没有,只有之前一段时间通过首单可以刷优惠,之后也修复了. 身边的同学也很多都在用.方便省 ...

  3. *.db-journal 是什么(android sqlite )数据库删除缓存

    sqlite的官方文档,发现该文件是sqlite的一个临时的日志文件,主要用于sqlite数据库的事务回滚操作了.在事务开始时产生,在事务操作完毕时自动删除,当程序发生崩溃或一些意外情况让程序非法结束 ...

  4. TSP-旅行商问题

    #include <iostream> #include <vector> #include <algorithm> using namespace std; in ...

  5. AWS中的Internet 网关

    nternet 网关是一种横向扩展.支持冗余且高度可用的 VPC 组件,可实现 VPC 中的实例与 Internet 之间的通信.因此它不会对网络流量造成可用性风险或带宽限制. Internet 网关 ...

  6. 【iOS】OC-AFNetworking 2.0 跟踪文件上传进度

    我是较新的 AFNetworking 2.0.使用下面的代码片段,我已经能够成功地将一张照片上传到我的 url.我想要跟踪的增量上载进度,但我找不到这样做 2.0 版的示例.我的应用程序是 iOS 7 ...

  7. 配置SpringAop时需要用到的AspectJ表达式

    Aspectj切入点语法定义 在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点" 例如定义切入点表达式  execu ...

  8. TensorFlow-谷歌深度学习库 手把手教你如何使用谷歌深度学习云平台

    自己的电脑跑cnn, rnn太慢? 还在为自己电脑没有好的gpu而苦恼? 程序一跑一俩天连睡觉也要开着电脑训练? 如果你有这些烦恼何不考虑考虑使用谷歌的云平台呢?注册之后即送300美元噢-下面我就来介 ...

  9. 吝啬的国度 nyoj

    吝啬的国度 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市, ...

  10. centos7 安装docker

    1.首先cent7 基本是在vm上完全安装'. 2.参考官方网站安装 1.https://wiki.centos.org/AdditionalResources/Repositories OS req ...