正式准备非常に写题前,先立个flag,倒过来写hdu(笑~)先是最后一页的第一题(大笑~)mustedge mustedge(这题的求解受到https://post.icpc-camp.org/d/724-hdoj-6200-mustedge-mustedge-mustedge的启发)
以及可以看http://blog.csdn.net/luotuoqingshan/article/details/77981430的标准程序
题面:
Give an connected undirected graph with
n
nodes and
m
edges, (
n,m≤105
) which has no selfloops or multiple edges
initially
.
Now we have
q
operations (
q≤105
):
⋅1 u v
: add an undirected edge from
u
to
v
;
(u≠v&&1≤u,v≤n)
⋅2 u v
: count the number of
mustedges
from
u
to
v
;
(1≤u,v≤n)
.
mustedge
: we define set
Ei
as a path from
u
to
v
which contain edges in this path, and
|∩k1Ei|
is the number of
mustedges
.
|x|
means size of set
x
, and
E1,E2…Ek
means all the paths.
It's guaranteed that
∑n,∑m,∑q≤106
Please note that maybe there are more than one edges between two nodes after we add edges. They are not the same, which means they can be in a set at the same time. Read the sample data for more information.
思维过程:关键字:联通无向简单图,加边,查询点u到点v的所有路径的必经边数;
简化题意:引理一:一条边如果作为某两个点的必经边,那么对于任意两个不同点如果改边在这两点间的某一路径上,那么该边也是这两个点的必经边;
因为如果边不在两点的任意路径上,那么它并不会加入查询。所以我们可以将一个图上的边分为两类必经边(绝对)和不必经过的边(绝对);
那么我们要做的就是对一个图G进行边的分类,然后统计随便某一路径上的必经边就行了;我们取名必经边叫白边,不必经边叫黑边;
解法:首先对于最简单的联通图——树,显然都是白边,所以我们只要统计u,v路径上有多少条边,这是标准的树状数组的问题了;
如果不是树呢?假设有它的某一生成树,然后再每次补上一条边,发现有一个变化,即u,v两点加边后它们和它们的lca构成了一个三角形的环,其他边没有影响,环上的边都变为黑(注意加边都是黑边),并且每次加边可以看作独立。所以只要我们提前求出u,v两点的lca再根据维护节点到根的边数由下面的公式update(u,-1),update(v,-1),update(lca,1),update(lca,1)维护即可,计算则由sum(u)+sum(v)-sum(lca)得出;最好的求lca自然是数剖啦,即为分类;
代码:
数剖求lca:
int head[2*maxn],to[maxn],son[maxn],siz[maxn];
int f[maxn],dep[maxn],tid[maxn],ran[maxn];
int tep[maxn],nex[2*maxn],tim,edge;
int num[maxn],tidr[maxn],rt[2*maxn];
void Init(){
memset(head, -1, sizeof(head));
memset(son, -1, sizeof(son));
tim=edge=0;
}
void dfs1(int u,int father,int d){
dep[u]=d;f[u]=father;siz[u]=-1;
for (int i=head[u]; ~i; i=nex[i]) {
int v=to[u];
if (v==father) {
continue;
}
dfs1(v, u, d+1);
siz[u]+=siz[v];
if (son[u]==-1||siz[v]>siz[son[u]]) {
son[u]=v;
}
}
}
void dfs2(int u,int tp){
tep[u]=tp;tid[u]=++tim;ran[tim]=u;
if (son[u]==-1) {
return;
}
dfs2(son[u], tp);
for (int i=head[u]; ~i; i=nex[i]) {
if (to[i]==son[u]||fa[u]==to[i]) {
continue;
}
dfs2(to[i], to[i]);
}
tidr[u]=tim;
}
int lca(int x,int y){
while (tep[x]!=tep[y]) {
if (dep[tep[x]]<dep[tep[y]]) {
swap(x, y);
}
x=fa[tep[x]];
}
return x;
}
树状数组:
int cost[maxn];
int lowbit(int x){
return x&-x;
}
void add(int x,int val){
while (x<=tim) {
cost[x]+=val;
x+=lowbit(x);
}
}
void update(int l,int r,int d){
add(l, d);add(r+1, -d);
}
int sum(int x){
int ans=0;
while (x>0) {
ans+=cost[x];
x+=lowbit(x);
}
return ans;
}
好啦~~拜拜