题面

传送门

分析

用Tarjan求出割点,对点-双连通分量(v-DCC)进行缩点,图会变成一棵树

注意v-DCC的缩点和e-DCC不同,因为一个割点可能属于多个v-DCC

设图中共有p个割点和t个v-DCC,我们建立一张包含p+t个点的新图,并将每个割点和包含它的所有v-DCC连边

缩点后原图中一般点的编号为v-DCC的编号,第i个割点的编号为(v-DCC个数+i)

对于原图上的一条路径(u,v),找到u,v对应的新编号,用树上差分算法更新路径上的所有点,使次数+1

为了处理若u,v不是割点,无法更新u,v的访问次数(因为在新图上v-DCC上的所有点被缩成了一个大点,而我们却要对点u,v单独进行更新

因此,我们在原图上建立一个数组graph_count,记录第i号节点(不是割点)的访问次数

输出答案时:

-若i是割点,直接输出树上对应的割点的访问次数

-否则输出graph_count[i]

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#define maxn 200005
#define maxm 200005
#define maxlog 32
using namespace std;
int n,m,q;
inline int qread(){
int x=0,sign=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*sign;
} struct graph {
struct edge {
int from;
int to;
int next;
} E[maxm<<1];
int head[maxn];
int ecnt;
void add_edge(int u,int v) {
ecnt++;
E[ecnt].from=u;
E[ecnt].to=v;
E[ecnt].next=head[u];
head[u]=ecnt;
}
graph(){
memset(head,0,sizeof(head));
memset(E,0,sizeof(E));
ecnt=1;
}
};
graph G,T; int tim,cnt,newn;
int dfn[maxn];
int low[maxn];
int cut[maxn];
int new_id[maxn];
int belong[maxn];
stack<int>s;
vector<int>v_dcc[maxn];
void tarjan(int x){
int flag=0;
dfn[x]=low[x]=++tim;
s.push(x);
for(int i=G.head[x];i;i=G.E[i].next){
int y=G.E[i].to;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(dfn[x]<=low[y]){
flag++;
if(x!=1||flag>1) cut[x]=1;
cnt++;
int z;
do{
z=s.top();
s.pop();
v_dcc[cnt].push_back(z);
}while(z!=y);
v_dcc[cnt].push_back(x);
}
}else low[x]=min(low[x],dfn[y]);
}
} void graph_to_tree(){
tim=cnt=0;
tarjan(1);
newn=cnt;
for(int i=1;i<=n;i++){
if(cut[i]){
belong[i]=++newn;
}
}
for(int i=1;i<=cnt;i++){
for(int j=0;j<v_dcc[i].size();j++){
int x=v_dcc[i][j];
if(cut[x]){
T.add_edge(i,belong[x]);
T.add_edge(belong[x],i);
}
else belong[x]=i;
}
}
} int graph_count[maxn];
int tree_count[maxn];
int deep[maxn];
int anc[maxn][maxlog];
void lca_init(int x,int fa){
deep[x]=deep[fa]+1;
anc[x][0]=fa;
for(int i=1;i<=20;i++){
anc[x][i]=anc[anc[x][i-1]][i-1];
}
for(int i=T.head[x];i;i=T.E[i].next){
int y=T.E[i].to;
if(y!=fa){
lca_init(y,x);
}
}
} int lca(int x,int y){
if(deep[x]<deep[y]) swap(x,y);
for(int i=20;i>=0;i--){
if(deep[anc[x][i]]>=deep[y]){
x=anc[x][i];
}
}
if(x==y) return x;
for(int i=20;i>=0;i--){
if(anc[x][i]!=anc[y][i]){
x=anc[x][i];
y=anc[y][i];
}
}
return anc[x][0];
} void add_route(int u,int v){
int l=lca(u,v);
tree_count[l]--;
tree_count[anc[l][0]]--;
tree_count[u]++;
tree_count[v]++;
} void sum_up(int x,int fa){
for(int i=T.head[x];i;i=T.E[i].next){
int y=T.E[i].to;
if(y!=fa){
sum_up(y,x);
tree_count[x]+=tree_count[y];
}
}
}
int main() {
int u,v,nu,nv;
n=qread();
m=qread();
q=qread();
for(int i=1;i<=m;i++){
u=qread();
v=qread();
G.add_edge(u,v);
G.add_edge(v,u);
}
graph_to_tree();
lca_init(1,0);
for(int i=1;i<=q;i++){
u=qread();
v=qread();
nu=belong[u];
nv=belong[v];
add_route(nu,nv);
if(!cut[u]) graph_count[u]++;
if(!cut[v]) graph_count[v]++;
}
sum_up(1,0);
for(int i=1;i<=n;i++){
if(cut[i]){
graph_count[i]=tree_count[belong[i]];
}
}
for(int i=1;i<=n;i++){
printf("%d\n",graph_count[i]);
}
}

BZOJ 3331 (Tarjan缩点+树上差分)的更多相关文章

  1. BZOJ 3307 雨天的尾巴 (树上差分+线段树合并)

    题目大意:给你一棵树,树上一共n个节点,共m次操作,每次操作给一条链上的所有节点分配一个权值,求所有节点被分配到所有的权值里,出现次数最多的权值是多少,如果出现次数相同就输出最小的. (我辣鸡bzoj ...

  2. [BZOJ2427][HAOI2010]软件安装-tarjan缩点-树上dp

    <题面> 这个题真伤人 之前Tarjan和树规都没学好,吃了不少亏,仔仔细细的搞了一天,收获颇丰 先来一个Tarjan的链接:$\mathbb{O}$ 题目的数据比较友好: $dp$不对: ...

  3. BZOJ 1179 (Tarjan缩点+DP)

    题面 传送门 分析 由于一个点可以经过多次,显然每个环都会被走一遍. 考虑缩点,将每个强连通分量缩成一个点,点权为联通分量上的所有点之和 缩点后的图是一个有向无环图(DAG) 可拓扑排序,按照拓扑序进 ...

  4. bzoj 2783: [JLOI2012]树【树上差分】

    注意是等于s不是大于s dfs,用set或者map存这条链到root的点权和sum[u],更新答案的时候查一下有没有s-sum[u]即可 #include<iostream> #inclu ...

  5. BZOJ 3331 [BeiJing2013]压力-Tarjan + 树上差分

    Solution Tarjan 点双缩点, 加上树上差分计算. 注意特判... 我特判挂了好久呜呜呜 Code #include<cstdio> #include<cstring&g ...

  6. BZOJ 压力 tarjan 点双联通分量+树上差分+圆方树

    题意 如今,路由器和交换机构建起了互联网的骨架.处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量. 他们每天都生活在巨大的压力之下.小强建立了一个模型.这世界上有N个网络设备, ...

  7. [Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分)

    [Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分) 题面 给出一个无向图,以及q条有向路径.问是否存在一种给边定向的方案,使得 ...

  8. BZOJ 1051 受欢迎的牛(Tarjan缩点)

    1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4573  Solved: 2428 [Submit][S ...

  9. BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MB Submit: 1388  Solved: 860 [Submit][Stat ...

随机推荐

  1. PgSQL · 特性分析 · PG主备流复制机制

    原文地址:http://mysql.taobao.org/monthly/2015/10/04/ PostgreSQL在9.0之后引入了主备流复制机制,通过流复制,备库不断的从主库同步相应的数据,并在 ...

  2. 2018-10-25-weekly

    Algorithm 94. 二叉树的中序遍历 What 给定一个二叉树,返回它的中序遍历. How 二叉树的中序遍历顺序为左-根-右,可以用递归来解,对左子结点调用递归函数,根节点访问值,右子节点再调 ...

  3. CF1009F Dominant Indices 长链剖分

    题目传送门 https://codeforces.com/contest/1009/problem/F 题解 长链剖分的板子吧. 令 \(dp[x][i]\) 表示 \(x\) 的子树中的深度为 \( ...

  4. css 表单头部固定

    原创 https://blog.csdn.net/q3585914/article/details/69946478 table表头和首列的表格固定-CSS实现的Table表头固定 原创 2017年0 ...

  5. bzoj2460题解

    [题意分析] 给你一个可重复数集,要求从中选取一个关于异或空间线性无关的子集,使子集的权值和最大. [解题思路] 定义:一个有序对(S,I)称为拟阵当且仅当该有序对满足以下性质: 1.有穷性:S是一个 ...

  6. 【HDOJ6681】Rikka with Cake(扫描线,线段树)

    题意:给定一个n*m的平面,有k条垂直或平行的直线,问将平面分成了几个互不联通的部分 n,m<=1e9,k<=1e5 思路: 刻在DNA里的二维数点 #include<bits/st ...

  7. 无题II

    无题II Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  8. [CSP-S模拟测试]:折纸(模拟)

    题目描述 小$s$很喜欢折纸.有一天,他得到了一条很长的纸带,他把它从左向右均匀划分为$N$个单位长度,并且在每份的边界处分别标上数字$0\sim n$.然后小$s$开始无聊的折纸,每次他都会选择一个 ...

  9. CocoaPods进阶:本地包管理

    http://www.iwangke.me/2013/04/18/advanced-cocoapods/ 粉笔网的iOS工程师唐巧曾经写过一篇blog<使用CocoaPods来做iOS程序的包依 ...

  10. scrapy中的cookies参数详解

    COOKIES_ENABLED 默认: True 是否启用cookiesmiddleware.如果关闭,cookies将不会发送给web server. COOKIES_DEBUG 默认: False ...