好久不写图论题好虚啊,m打成n RE了3次QAQ人生耻辱啊。
首先假设没有删边,显然答案是两点间桥的数量。
于是求边双连通分量,缩点缩边,只留下桥。
所以剩下的肯定是树啦。
于是询问变成了求树上两点间距离,求下LCA就可以直接做了。
但是还有删边操作。
删边肯定不好处理。
反过来改成加边操作。
两点与LCA形成了一个边双联通分量,于是把他们缩起来。
直接缩不可取,考虑缩点的后果是子树被提升了相同的高度,于是考虑把点u向祖先v缩边,step by step,缩掉u-fa(u)这条边的后果是u这颗子树的高度被提升了dep(u)-dep(fa(u)),dfs序+BIT维护子树高度,差分之后变成区间修改+单点查询。
然后由于每个点都至多被缩一次(加个并查集维护一下)所以是nlogn的。
所以总的也就是nlogn了。
made竟然写了180多行
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<stack> #define mk(x,y) make_pair(x,y) using namespace std; const int N=30000+5; const int M=100000+5; struct Edge{int to,next;}e[M<<1]; int head[N],cnt; void ins(int u,int v){ e[++cnt]=(Edge){v,head[u]};head[u]=cnt; } void insert(int u,int v){ ins(u,v);ins(v,u); } int dep[N],son[N],siz[N],st[N],ed[N],fa[N],top[N],sz; void dfs(int u){ son[u]=0;siz[u]=1; for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1; dfs(v); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } void dfs(int u,int tp){ st[u]=++sz;top[u]=tp; if(son[u])dfs(son[u],tp); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v!=son[u]&&v!=fa[u]) dfs(v,v); } ed[u]=sz; } int lca(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); u=fa[top[u]]; } if(dep[u]>dep[v])swap(u,v); return u; } struct BIT{ int d[N]; #define lb(x) (x&-x) void add(int x,int v){ for(;x<=sz;x+=lb(x))d[x]+=v; } int sum(int x){ int ans=0; for(;x>0;x-=lb(x))ans+=d[x]; return ans; } void add(int l,int r,int x){ add(l,x);add(r+1,-x); } int query(int x){ return sum(st[x]); } }T; void up(int x,int d){ T.add(st[x],ed[x],-d); } int pa[N]; int find(int x){ return pa[x]==x?x:pa[x]=find(pa[x]); } void merge(int f,int t){ while(f!=t){ up(f,T.query(f)-T.query(find(fa[f]))); pa[f]=t; f=find(fa[f]); } } void add(int u,int v){ u=find(u);v=find(v); if(u==v)return; int w=lca(u,v);w=find(w); merge(u,w);merge(v,w); } int query(int x,int y){ x=find(x);y=find(y); if(x==y)return 0; int w=lca(x,y);w=find(w); return T.query(x)+T.query(y)-2*T.query(w); } int bccno[N],dfn[N],dfs_clock,bcc_cnt; stack<int>s; int tarjan(int u,int fa){ int lowu=dfn[u]=++dfs_clock,child=0; s.push(u); for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(v==fa)continue; if(!dfn[v]){ int lowv=tarjan(v,u); lowu=min(lowu,lowv); if(lowv>dfn[u]){ bcc_cnt++; while(true){ int x=s.top();s.pop(); bccno[x]=bcc_cnt; if(x==v)break; } } }else lowu=min(lowu,dfn[v]); } if(fa<0&&child<2){ bcc_cnt++; while(true){ int x=s.top();s.pop(); bccno[x]=bcc_cnt; if(x==u)break; } } return lowu; } struct Query{ int c,x,y; }q[40005]; vector<int>g[N],del[N]; int ans[40005]; int main(){ //freopen("a.in","r",stdin); int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v;scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } for(int i=1;i<=n;i++){ sort(g[i].begin(),g[i].end()); del[i].resize(g[i].size()); } int k=0; while(++k){ scanf("%d",&q[k].c); if(q[k].c==-1)break; scanf("%d%d",&q[k].x,&q[k].y); if(q[k].c==0){ int it=lower_bound(g[q[k].x].begin(),g[q[k].x].end(),q[k].y)-g[q[k].x].begin(); del[q[k].x][it]=1; it=lower_bound(g[q[k].y].begin(),g[q[k].y].end(),q[k].x)-g[q[k].y].begin(); del[q[k].y][it]=1; } } for(int i=1;i<=n;i++){ for(int j=0;j<g[i].size();j++) if(!del[i][j]) ins(i,g[i][j]); g[i].clear(); } tarjan(1,-1); for(int u=1;u<=n;u++) for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(bccno[u]!=bccno[v]){ g[bccno[u]].push_back(bccno[v]); g[bccno[v]].push_back(bccno[u]); } } memset(head,0,sizeof(head));cnt=0; for(int i=1;i<=bcc_cnt;i++){ sort(g[i].begin(),g[i].end()); m=unique(g[i].begin(),g[i].end())-g[i].begin(); for(int j=0;j<m;j++) ins(i,g[i][j]); } dfs(1);dfs(1,1); for(int i=1;i<=sz;i++) T.add(st[i],st[i],dep[i]); for(int i=1;i<=sz;i++)pa[i]=i; for(int i=k-1;i>=1;i--) if(q[i].c) ans[i]=query(bccno[q[i].x],bccno[q[i].y]); else add(bccno[q[i].x],bccno[q[i].y]); for(int i=1;i<k;i++) if(q[i].c) printf("%d\n",ans[i]); return 0; }
原来可以直接树剖……果然是我太弱了
每次加边操作相当于是把u-lca(u,v)-v之间的所有边权都置为0(初始为1)
每次询问是询问两点间边权和
直接树剖啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
其实才多了20行,而且只慢了100MS
难道是我之前那个版本写挫了QAQ
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<stack> #define mk(x,y) make_pair(x,y) using namespace std; const int N=30000+5; const int M=100000+5; struct Edge{int to,next;}e[M<<1]; int head[N],cnt; void ins(int u,int v){ e[++cnt]=(Edge){v,head[u]};head[u]=cnt; } void insert(int u,int v){ ins(u,v);ins(v,u); } int dep[N],son[N],siz[N],pos[N],fa[N],top[N],sz; void dfs(int u){ son[u]=0;siz[u]=1; for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1; dfs(v); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } void dfs(int u,int tp){ pos[u]=++sz;top[u]=tp; if(son[u])dfs(son[u],tp); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v!=son[u]&&v!=fa[u]) dfs(v,v); } } struct Node{ int l,r,sum; bool flag; }tr[N<<2]; #define lc o<<1 #define rc o<<1|1 void pushup(int o){ tr[o].sum=tr[lc].sum+tr[rc].sum; } void pushdown(int o){ if(tr[o].flag){ tr[lc].flag=tr[rc].flag=true; tr[lc].sum=tr[rc].sum=0; tr[o].flag=0; } } void build(int o,int l,int r){ tr[o].l=l;tr[o].r=r; if(l==r)tr[o].sum=1; else{ int mid=l+r>>1; build(lc,l,mid);build(rc,mid+1,r); pushup(o); } } void modify(int o,int a,int b){ int l=tr[o].l,r=tr[o].r; if(l==a&&b==r){ tr[o].flag=1;tr[o].sum=0; }else{ int mid=l+r>>1; pushdown(o); if(b<=mid)modify(lc,a,b); else if(mid<a)modify(rc,a,b); else modify(lc,a,mid),modify(rc,mid+1,b); pushup(o); } } int sum(int o,int a,int b){ int l=tr[o].l,r=tr[o].r; if(l==a&&b==r)return tr[o].sum; else{ int mid=l+r>>1; pushdown(o); if(b<=mid)return sum(lc,a,b); else if(mid<a)return sum(rc,a,b); else return sum(lc,a,mid)+sum(rc,mid+1,b); } } void add(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); modify(1,pos[top[u]],pos[u]); u=fa[top[u]]; } if(u==v)return; if(dep[u]>dep[v])swap(u,v); modify(1,pos[son[u]],pos[v]); } int query(int u,int v){ int ans=0; while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); ans+=sum(1,pos[top[u]],pos[u]); u=fa[top[u]]; } if(u==v)return ans; if(dep[u]>dep[v])swap(u,v); ans+=sum(1,pos[son[u]],pos[v]); return ans; } int bccno[N],dfn[N],dfs_clock,bcc_cnt; stack<int>s; int tarjan(int u,int fa){ int lowu=dfn[u]=++dfs_clock,child=0; s.push(u); for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(v==fa)continue; if(!dfn[v]){ int lowv=tarjan(v,u); lowu=min(lowu,lowv); if(lowv>dfn[u]){ bcc_cnt++; while(true){ int x=s.top();s.pop(); bccno[x]=bcc_cnt; if(x==v)break; } } }else lowu=min(lowu,dfn[v]); } if(fa<0&&child<2){ bcc_cnt++; while(true){ int x=s.top();s.pop(); bccno[x]=bcc_cnt; if(x==u)break; } } return lowu; } struct Query{ int c,x,y; }q[40005]; vector<int>g[N],del[N]; int ans[40005]; int main(){ //freopen("a.in","r",stdin); int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v;scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } for(int i=1;i<=n;i++){ sort(g[i].begin(),g[i].end()); del[i].resize(g[i].size()); } int k=0; while(++k){ scanf("%d",&q[k].c); if(q[k].c==-1)break; scanf("%d%d",&q[k].x,&q[k].y); if(q[k].c==0){ int it=lower_bound(g[q[k].x].begin(),g[q[k].x].end(),q[k].y)-g[q[k].x].begin(); del[q[k].x][it]=1; it=lower_bound(g[q[k].y].begin(),g[q[k].y].end(),q[k].x)-g[q[k].y].begin(); del[q[k].y][it]=1; } } for(int i=1;i<=n;i++){ for(int j=0;j<g[i].size();j++) if(!del[i][j]) ins(i,g[i][j]); g[i].clear(); } tarjan(1,-1); for(int u=1;u<=n;u++) for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(bccno[u]!=bccno[v]){ g[bccno[u]].push_back(bccno[v]); g[bccno[v]].push_back(bccno[u]); } } memset(head,0,sizeof(head));cnt=0; for(int i=1;i<=bcc_cnt;i++){ sort(g[i].begin(),g[i].end()); m=unique(g[i].begin(),g[i].end())-g[i].begin(); for(int j=0;j<m;j++) ins(i,g[i][j]); } dfs(1);dfs(1,1); build(1,1,bcc_cnt); for(int i=k-1;i>=1;i--) if(q[i].c) ans[i]=query(bccno[q[i].x],bccno[q[i].y]); else add(bccno[q[i].x],bccno[q[i].y]); for(int i=1;i<k;i++) if(q[i].c) printf("%d\n",ans[i]); return 0; }