好久不写图论题好虚啊,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;
}