Description

A:一心一意

B:一个顶俩

最近QQ更新后那个成语接龙好像挺火的?但我只知道图论里一条边是一个顶俩个点的emm。

如果我给你一个n个点n-1条边的无向联通图,但是这里头有一些边是脆弱的。随时都面临崩坏的危险。

为了维持他们的连通性,善良的我又给了你m条紫水晶备用边(u,v)。我这里准备Q个问题,第i个问题为一个整数z(1≤z≤n−1)表示若第z条边崩坏了,你能选出多少条备用边保证图继续保持联通。

Input

第一行三个正整数表示n,m,Q

接下来n-1行每行两个整数x,y一条边。

下面m行每行两个整数u,v表示备用边。

接下来Q行,每行一个整数z表示询问。

1≤n,m,Q≤100000。保证数据合法。

Output

Q行,每行一个整数表示答案。

Sample Input

3 2 2
1 2
1 3
2 3
1 3
1
2

Sample Output

1
2

Hint

第一个问题把第1条边(1,2)删掉,你可以选择备用边(2,3)保证连通性。

第二个问题把第2条边(2,3)删掉,你可以随意选择一条备用边都能保证连通性。

题目分析

题意:给出一个有n个结点的树,同时给出m条备用边u,v,有q次询问,每次询问删除边x后,你能选出多少种方案只加一条备用边能保证图的联通。

思路:这个实际上是一个很裸的树链剖分,更新边权的树链剖分,主要难在想到这是一个树链剖分的题目。

注意到增加一条备用边(u,v)时,这条备用边可以在原u,v两点之间任意一条边被删除后使得整个图重新连通,因此,u到v路径上所有的边都可以用这条备用边修复删除自身后的图的连通性,那么问题摆明了就是一个更新边权的树链剖分了

对于每一条备用边(u,v),我们将原图中u,v之间的每一条边的边权加一,表示这一备用边可以用于修复删除这条边后的图的连通性,最后,问边(u,v)删除时,有多少种修复方案的时候,我们输出边(u,v)的边权即可。

(博主自言自语:对于更新边权的树链剖分,我们将边权存于这条边所连接的两个结点中深度更大的结点,这样一来我们更新同一条链上的边的边权的时候,更新的区间即为 [深度小的结点的重儿子的dfs序,深度大的结点的dfs序],所以实际上记录点权和边权的熟树链剖分代码大体上只有一处不同])

代码区

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip> #define bug cout << "**********" << endl
#define show(x, y) cout<<"["<<x<<","<<y<<"] "
#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + ;
const int Max = 1e5 + ; struct Tree
{
int deep, father, val; //结点深度,父节点,权值
int size, heavy; //以此结点为根节点的树的大小。重儿子的编号
int id, top; //对应于线段树上的编号(dfs序),链头编号
}tree[Max]; //原本树的结点信息 int n, m, q;
int toTree[Max],cnt; //记录dfs序对应的结点编号;记录dfs序,说到底,cnt最终还是等于n,在这个题目中,用处不大 //以下为线段树操作
struct Node
{
int l, r;
int sum, lazy;
}node[Max << ]; void build(int l, int r, int num)
{
node[num].l = l;
node[num].r = r;
node[num].lazy = ;
if (l == r)
{
node[num].sum = tree[toTree[l]].val; //初始化边权
return;
}
int mid = (l + r) >> ;
build(l, mid, num << );
build(mid + , r, num << | );
node[num].sum = node[num << ].sum + node[num << | ].sum; //sum记录区间和
} void push_down(int num)
{
if (node[num].lazy != )
{
int &lazy = node[num].lazy; node[num << ].sum += lazy; node[num << | ].sum += lazy; node[num << ].lazy += lazy;
node[num << | ].lazy += lazy; lazy = ;
}
} void upData(int l, int r, int val, int num) //更新区间,这个是模板的函数,其实这个题目只要单点更新即可,但对时间影响不大
{
if (l <= node[num].l && node[num].r <= r)
{
node[num].sum += val;
node[num].lazy += val;
return;
}
push_down(num);
int mid = (node[num].l + node[num].r) >> ; if (l <= mid)
upData(l, r, val, num << );
if (r > mid)
upData(l, r, val, num << | );
node[num].sum = node[num << ].sum + node[num << | ].sum;
} int query(int l, int r, int num) //查询区间和,模板查询函数,这里我们只用于单点查询
{
if (l <= node[num].l && node[num].r <= r)
return node[num].sum; push_down(num); int mid = (node[num].l + node[num].r) >> ;
int ans = ;
if (l <= mid)
ans += query(l, r, num << );
if (r > mid)
ans += query(l, r, num << | ); return ans;
} //以下为树链剖分的部分
struct Edge
{
int to, next;
}edge[Max << ]; //边 int head[Max], tot; void init()
{
memset(head, -, sizeof(head));tot = ;
} void add(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} void dfs1(int now, int fa, int deep)
{
tree[now].val = ; //初始化为0,这个是模板内容,可能边有初始值,不过这个题没有就对了
tree[now].father = fa;
tree[now].deep = deep;
tree[now].size = ;
tree[now].heavy = -; //初始化为无重边(也就是看作叶子节点了)
int max_son = -;
for (int i = head[now]; i != -; i = edge[i].next)
{
int v = edge[i].to;
if (v == fa) continue; dfs1(v, now, deep + ); tree[now].size += tree[v].size;
if (tree[v].size > max_son) //更新重边
tree[now].heavy = v, max_son = tree[v].size;
}
} void dfs2(int now, int top) //top为当前链的链头
{
tree[now].top = top;
tree[now].id = ++cnt;
if (tree[now].heavy == -) return; //叶子结点
dfs2(tree[now].heavy, top); //先处理重链
for (int i = head[now]; i != -; i = edge[i].next) //处理轻链
{
int v = edge[i].to;
if (v == tree[now].father || v == tree[now].heavy) continue;
dfs2(v, v); //此时v为一条轻链的链头(画一下就知道为什么了)
}
} void upData2(int s, int e, int val) //更新s->e上的结点,将dfs不连续的路径分为数个dfs序连续的路径,对这个数个dfs序连续的路径进行操作
{
while (tree[s].top != tree[e].top) //不断地将深度大的上移,使得最后两个点都在同一个链上
{
if (tree[tree[s].top].deep < tree[tree[e].top].deep) swap(s, e);
upData(tree[tree[s].top].id, tree[s].id, val, ); //同时更新分出来的dfs序连续的路径
s = tree[tree[s].top].father;
}
if (tree[s].deep > tree[e].deep) swap(s, e);
upData(tree[tree[s].heavy].id, tree[e].id, val, );
//这个地方就是更新边权和点权的区别了,由于我们将边权的值存于这条边深度更大的端点处
//因此我们更新点s,e之间的边的边权的时候,更新的边为e表示的这条边和s的重儿子表示的那条边之间的边
//对应的dfs序就是 tree[tree[s].heavy].id ~ tree[e].id, val 了
} int query2(int s, int e) //思路和upData2的一样:将dfs不连续的路径分为数个dfs序连续的路径,对这个数个dfs序连续的路径进行操作
{
int sum = ;
while (tree[s].top != tree[e].top)
{
if (tree[tree[s].top].deep < tree[tree[e].top].deep) swap(s, e);
sum += query(tree[tree[s].top].id, tree[s].id, );
s = tree[tree[s].top].father;
}
if (tree[s].deep > tree[e].deep) swap(s, e);
sum += query(tree[tree[s].heavy].id, tree[e].id, );
return sum;
} int u[Max],v[Max]; //记录边 int main()
{
#ifdef LOCAL
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif
while (scanf("%d%d%d", &n, &m, &q) != EOF)
{
init();
for (int i = ;i < n;i++)
{
scanf("%d%d", u+i, v+i); //因为后面根据边的编号来查询,所以用数组记录一下
add(u[i], v[i]);add(v[i], u[i]);
}
dfs1(, -, ); //先预处理出每个结点的基本信息,比如每个根结点对应的重边,以为构建链做准备
dfs2(, ); //根据之前已经求出的每个结点的信息,获得链上结点dfs连续的dfs序
build(, n, ); //根据之前得到的dfs序构建线段树 for(int i = , x, y; i <= m ;i ++)
{
scanf("%d%d",&x,&y);
upData2(x,y,); //给区间每条边的边权加一
}
for(int i =,x ;i <= q; i ++)
{
scanf("%d",&x);
printf("%d\n",query2(u[x],v[x]));
}
}
return ;
}

CSUST 2012 一个顶俩 (本校OJ题)(思维+树链剖分)的更多相关文章

  1. jzoj5987. 【WC2019模拟2019.1.4】仙人掌毒题 (树链剖分+概率期望+容斥)

    题面 题解 又一道全场切的题目我连题目都没看懂--细节真多-- 先考虑怎么维护仙人掌.在线可以用LCT,或者像我代码里先离线,并按时间求出一棵最小生成树(或者一个森林),然后树链剖分.如果一条边不是生 ...

  2. HDU 3966 Aragorn's Story(模板题)【树链剖分】+【线段树】

    <题目链接> 题目大意: 给定一颗带点权的树,进行两种操作,一是给定树上一段路径,对其上每个点的点权增加或者减少一个数,二是对某个编号点的点权进行查询. 解题分析: 树链剖分的模板题,还不 ...

  3. 洛谷树剖模板题 P3384 | 树链剖分

    原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...

  4. LOJ #6669 Nauuo and Binary Tree (交互题、树链剖分)

    题目链接 https://loj.ac/problem/6669 题解 Orz yyf太神了,出这种又有意思又有意义的好题造福人类-- 首先\(n\)次询问求出所有节点的深度. 考虑按深度扩展(BFS ...

  5. Luogu3676 小清新数据结构题(树链剖分+线段树)

    先不考虑换根.考虑修改某个点权值对答案的影响.显然这只会改变其祖先的子树权值和,设某祖先原子树权值和为s,修改后权值增加了x,则对答案的影响为(s+x)2-s2=2sx+x2.可以发现只要维护每个点到 ...

  6. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

    [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...

  7. 洛谷 P3384 树链剖分(模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  8. HDU 5029 Relief grain --树链剖分第一题

    题意:给一棵树,每次给两个节点间的所有节点发放第k种东西,问最后每个节点拿到的最多的东西是哪种. 解法:解决树的路径上的修改查询问题一般用到的是树链剖分+线段树,以前不会写,后来学了一下树链剖分,感觉 ...

  9. 树链剖分的一种妙用与一类树链修改单点查询问题的时间复杂度优化——2018ACM陕西邀请赛J题

    题目描述 有一棵树,每个结点有一个灯(初始均是关着的).每个灯能对该位置和相邻结点贡献1的亮度.现有两种操作: (1)将一条链上的灯状态翻转,开变关.关变开: (2)查询一个结点的亮度. 数据规模:\ ...

随机推荐

  1. TensorFlow使用记录 (九): 模型保存与恢复

    模型文件 tensorflow 训练保存的模型注意包含两个部分:网络结构和参数值. .meta .meta 文件以 “protocol buffer”格式保存了整个模型的结构图,模型上定义的操作等信息 ...

  2. vue-cli3项目中引入jquery 以及如何引进bootstrap

    1.安装jquery npm install jquery --save 2.或则在package.json中指定版本号,然后运行npm install命令 "dependencies&qu ...

  3. Android中的“再按一次返回键退出程序”代码实现

    1 用户在退出应用前给出一个提示是很有必要的,因为可能是用户并不真的想退出,而只是一不小心按下了返回键,大部分应用也是这么做的,但也有些应用的做法是在应用退出去前给出一个Dialog,我觉得这样不太友 ...

  4. JavaWeb_(Struts2框架)Servlet与Struts区别

    JavaWeb_(SSH)使用Servlet实现用户的登陆 传送门 JavaWeb_(SSH)使用Struts框架实现用户的登陆 传送门 MySQL数据库中存在Gary用户,密码为123:第一次登陆时 ...

  5. Keras学习笔记二:保存本地模型和调用本地模型

    使用深度学习模型时当然希望可以保存下训练好的模型,需要的时候直接调用,不再重新训练 一.保存模型到本地 以mnist数据集下的AutoEncoder 去噪为例.添加: file_path=" ...

  6. vue的通信方式(二)---祖父孙三个级别的之间的隔代通信

    在之前的文章中我们提到了vue常用的几种通信方式,如父子,子父,以及兄弟组件之间的通信,可以通过这个传送门了解他们:Vue通信方式(一) 当我们如果遇到祖组件,父组件,孙组件,三个级别嵌套时,我们该怎 ...

  7. Nginx常见配置

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  8. 强大的unique

    强大的unique 两道红题为例眼熟一下unique P1138 第k小整数 题解 这里用到了STL的去重函数哦 unique 首先你有一个待处理的数组 a[n] 一定要先排序鸭  sort( a+1 ...

  9. C++中的to_string()

    目录 C++中的to_string() 注:原创不易,转载请务必注明原作者和出处,感谢支持! C++中的to_string() C++中的 to_string()系列函数将数值转换成字符串形式.注意, ...

  10. C#产生随机验证码的代码

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...