bzoj 3331 压力题解
这题目其实说实话还是很简单的,吗?
看到跟点有关系,其实就是求过程中的割点有多少个,这就直接用一个点双缩点,在缩点后,这个图就变成一个树了,而这里就直接用一个树上差分就可以解决。当然本身这个节点也是要记的。
(好吧,边双写了 20pts 的傻子也是在这里写题解了)。
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N=2E5+5;
int n,m,q,rt,id[N],low[N],st[N],dfn[N],cnt,top,dc,f[N][21],dep[N],cut[N],pre[N],res[N],px[N];
vector<pii>e[N];
vector<int>g[2*N],h[N];
void tarjan(int u,int ID) {
low[u]=dfn[u]=++cnt;
st[++top]=u;
int f=0,y;
for(auto tmp:e[u]) {
int v=tmp.first,I=tmp.second;
if(I==(ID^1))continue;
if(!dfn[v]) {
tarjan(v,I);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]) {
f++,++dc;
cut[u] =(f>1 || u!=1);
do {
y=st[top--],h[dc].push_back(y) ;
} while(y!=v);
h[dc].push_back(u);
}
} else low[u]=min(low[u],dfn[v]);
}
}
void dfs(int rt,int fa){
dep[rt]=dep[fa]+1;
f[rt][0]=fa;
for(int i=1;i<=20;i++)
f[rt][i]=f[f[rt][i-1]][i-1];
for(int p:g[rt]){
if(p==fa)continue;
dfs(p,rt);
}
}
void redfs(int rt,int fa){
for(int p:g[rt]){
if(p==fa)continue;
redfs(p,rt);
pre[rt]+=pre[p];
}
}
int LCA(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int d=dep[u]-dep[v];
for(int i=20;i>=0;i--)
if(d&(1<<i))u=f[u][i];
if(u==v)return u;
for(int i=20;i>=0;i--)
if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
return f[u][0];
}
signed main() {
scanf("%d%d%d",&n,&m,&q);
for(int i=1,x,y; i<=m; i++) {
scanf("%d%d",&x,&y);
e[x].push_back({y,2*i});
e[y].push_back({x,2*i+1});
}
rt=1,tarjan(1,0);
int num=dc;
for(int i=1;i<=n;i++)if(cut[i])px[i]=++num;
for(int i=1;i<=dc;i++)for(int j:h[i]){
if(cut[j])g[i].push_back(px[j]),g[px[j]].push_back(i);
else id[j]=i;
}
dfs(1,0);
while(q--){
int x,y;
scanf("%d%d",&x,&y);
if(!cut[x])res[x]++,x=id[x];
else x=px[x];
if(!cut[y])res[y]++,y=id[y];
else y=px[y];
int lca=LCA(x,y);
++pre[x],++pre[y],--pre[lca],--pre[f[lca][0]];
}
redfs(1,0);
for(int i=1;i<=n;i++){
if(cut[i])cout<<pre[px[i]]<<endl;
else cout<<res[i]<<endl;
}
return 0;
}

浙公网安备 33010602011771号