3331: [BeiJing2013]压力

时间:2021-10-19 14:05:41

3331: [BeiJing2013]压力

LCA+树上差分,和之前类似的题差不多,就是多了个v-dcc缩点,唯一要注意的就是判断是否是割点,对于不是割点的点,如果他是起点或重点,ans++,和差分没有关系,对于割点,则需要用到差分,注意割点与非割点的答案要分开存储,否则会死的。

另外要注意的是数组的大小,开始我因为数组开小了然后MLE了(对,就是这么神奇),因为如果退化成一条链,缩完点后的点数会比缩点前还要多。

#include<iostream>
#include<cstdio>
#include<vector>
#define MAXN 300010
using namespace std;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
#define u2(x) ed2[x].u
#define v2(x) ed2[x].v
#define n2(x) ed2[x].nxt
}ed[MAXN*4],ed2[MAXN*4];
int first[MAXN],num_e;
#define f(x) first[x]
int first2[MAXN],num_e2;
#define f2(x) first2[x]
int n,m,q; int dfn[MAXN],low[MAXN],num,root;
int stack[MAXN],top,cnt;
bool iscut[MAXN];
vector<int> dcc[MAXN];
void tarjan(int x)
{
dfn[x]=low[x]=++num;
stack[++top]=x;
if(x==root&&!f(x)){dcc[++cnt].push_back(x);return;}
int flag=0;
for(int i=f(x);i;i=n(i))
if(!dfn[v(i)])
{
tarjan(v(i));low[x]=min(low[x],low[v(i)]);
if(low[v(i)]>=dfn[x])
{
flag++;
if(x!=root||flag>1)iscut[x]=1;
cnt++;int z;
do{dcc[cnt].push_back(z=stack[top--]);}while(z!=v(i));
dcc[cnt].push_back(x);
}
}
else low[x]=min(low[x],dfn[v(i)]);
}
int new_id[MAXN],c[MAXN];
int f[MAXN][20],dep[MAXN];
void dfs(int x,int fa,int deep)
{
f[x][0]=fa;dep[x]=deep;
for(int i=f2(x);i;i=n2(i))
if(v2(i)!=fa)
dfs(v2(i),x,deep+1);
}
int ans[MAXN],eans[MAXN];
void dfs2(int x,int fa)
{
for(int i=f2(x);i;i=n2(i))
if(v2(i)!=fa)
{
dfs2(v2(i),x);
eans[x]+=eans[v2(i)];
}
}
int LCA(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
while(dep[x]!=dep[y])
for(int i=0;;i++)
if(dep[f[y][i]]<dep[x])
{y=f[y][i-1];break;}
if(x==y)return x;
while(f[x][0]!=f[y][0])
for(int i=0;;i++)
if(f[x][i]==f[y][i])
{x=f[x][i-1],y=f[y][i-1];break;}
return f[x][0];
}
inline void add(int u,int v);
inline void add2(int u,int v);
signed main()
{
// freopen("in.txt","r",stdin); scanf("%d%d%d",&n,&m,&q);
int a,b;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
for(int i=1;i<=n;i++)
if(!dfn[i]){root=i;tarjan(i);}
num=cnt;
for(int i=1;i<=n;i++)
if(iscut[i])new_id[i]=++num;
for(int i=1;i<=cnt;i++)
for(int j=0;j<dcc[i].size();j++)
{
int x=dcc[i][j];
if(iscut[x])
add2(i,new_id[x]),add2(new_id[x],i);
else c[dcc[i][j]]=i;
}
dfs(1,0,1);
for(int j=1;j<20;j++)
for(int i=1;i<=num;i++)
f[i][j]=f[f[i][j-1]][j-1];
for(int i=1;i<=q;i++)
{
scanf("%d%d",&a,&b);
if(!iscut[a])ans[a]++;
if(!iscut[b])ans[b]++;
int ca=iscut[a]?new_id[a]:c[a],
cb=iscut[b]?new_id[b]:c[b],
lca=LCA(ca,cb);
eans[ca]++,eans[cb]++;
eans[f[lca][0]]--,eans[lca]--;
}
dfs2(1,0);
for(int i=1;i<=n;i++)
printf("%d\n",iscut[i]?eans[new_id[i]]:ans[i]);
}
inline void add(int u,int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
inline void add2(int u,int v)
{
++num_e2;
u2(num_e2)=u;
v2(num_e2)=v;
n2(num_e2)=f2(u);
f2(u)=num_e2;
}