题目大意

给定一棵基环树, 问你有多少条路径的长度\(\ge K\).

点数\(\le 10^5\)

Solution

基环树分治模板题.

我是这样做的: 加边的时候用并查集维护点的连通性, 少加入环上的一条边, 使得基环图变为树的形态.

首先在树上进行一次常规的树分治. 我们能得到不经过被删除的一条边的满足要求的路径数量;

然后我们根据被删去的边的两个端点找到环, 在环上求出经过被删去边的路径数量即可.

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm> using namespace std;
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1; char c;
while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
const int N = (int)4e5;
int n, m, len;
int lp[2];
long long ans;
struct disjointSet
{
int pre[N + 1];
inline void initialize() {for(int i = 1; i <= n; ++ i) pre[i] = i;}
inline int access(int u)
{
if(pre[u] != u) pre[u] = access(pre[u]);
return pre[u];
}
}st;
struct segmentTree
{
struct node
{
node *suc[2];
int sz;
inline node() {for(int i = 0; i < 2; ++ i) suc[i] = NULL; sz = 0;}
}*rt;
void clear(node *u)
{
for(int i = 0; i < 2; ++ i) if(u->suc[i] != NULL) clear(u->suc[i]);
delete u;
}
inline void clear()
{
if(rt != NULL) clear(rt); rt = NULL; // 记得要把rt复位, 否则就会乱套啦
}
node* modify(node *u, int L, int R, int pos, int dlt)
{
if(u == NULL) u = new node;
u->sz += dlt;
if(L == R) return u;
if(pos <= L + R >> 1) u->suc[0] = modify(u->suc[0], L, L + R >> 1, pos, dlt);
else u->suc[1] = modify(u->suc[1], (L + R >> 1) + 1, R, pos, dlt);
return u;
}
inline void modify(int pos, int dlt)
{
rt = modify(rt, 1, n, pos, dlt);
}
int query(node *u, int L, int R, int pos)
{
if(u == NULL) return 0;
if(L >= pos) return u->sz;
if(pos > L + R >> 1) return query(u->suc[1], (L + R >> 1) + 1, R, pos);
else return query(u->suc[0], L, L + R >> 1, pos) + query(u->suc[1], (L + R >> 1) + 1, R, pos);
}
inline int query(int pos)
{
return query(rt, 1, n, pos);
}
}seg;
struct tree
{
struct node
{
vector<int> edg;
int flg, mx, sz;
int nxt, lst, len;
inline node() {edg.clear(); flg = 0;}
}nd[N + 1];
inline void addEdge(int u, int v)
{
int rtU = st.access(u), rtV = st.access(v);
if(rtU == rtV)
{
lp[0] = u, lp[1] = v;
return;
}
st.pre[rtU] = rtV;
nd[u].edg.push_back(v); nd[v].edg.push_back(u);
}
void getSize(int u, int pre)
{
// printf("%d\n", u);
nd[u].sz = 1; nd[u].mx = 0;
for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg) getSize(v, u), nd[u].sz += nd[v].sz, nd[u].mx = max(nd[v].sz, nd[u].mx);
// for(vector<int>::iterator p = nd[u].edg.begin(); p != nd[u].edg.end(); ++ p)
// if(*p != pre && ! nd[*p].flg) getSize(*p, u), nd[u].sz += nd[*p].sz, nd[u].mx = max(nd[*p].sz, nd[u].mx);
}
int getRoot(int u, int pre, int cen)
{
nd[u].mx = max(nd[u].mx, nd[cen].sz - nd[u].sz);
int res = u;
for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg)
{
int cur = getRoot(v, u, cen);
if(nd[cur].mx < nd[res].mx) res = cur;
}
return res;
}
void getAnswer(int u, int pre, int cur)
{
ans += seg.query(len - cur);
for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg) getAnswer(v, u, cur + 1);
}
void update(int u, int pre, int cur)
{
seg.modify(cur, 1);
for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg) update(v, u, cur + 1);
}
inline void work(int u)
{
getSize(u, -1);
u = getRoot(u, -1, u); nd[u].flg = 1;
seg.clear(); seg.modify(1, 1);
for(auto v : nd[u].edg) if(! nd[v].flg)
{
getAnswer(v, u, 1);
update(v, u, 2);
}
for(auto v : nd[u].edg) if(! nd[v].flg) work(v);
}
inline void work() {work(1);}
int getLoop(int u, int pre)
{
nd[u].lst = pre; nd[u].nxt = -1;
if(u == lp[1]) return u;
for(auto v : nd[u].edg) if(v != pre && nd[u].nxt == -1) nd[u].nxt = getLoop(v, u);
if(~ nd[u].nxt) return u;
nd[u].lst = -1;
return -1;
}
void getOutsideSize(int u, int pre, int cur, int opt)
{
seg.modify(cur, opt);
for(auto v : nd[u].edg) if(v != pre) getOutsideSize(v, u, cur + 1, opt);
}
void getOutsideSize(int u, int cur)
{
seg.modify(cur, 1);
nd[u].len = cur;
for(auto v : nd[u].edg) if(v != nd[u].nxt && v != nd[u].lst) getOutsideSize(v, u, cur + 1, 1);
if(~ nd[u].lst) getOutsideSize(nd[u].lst, cur + 1);
}
void getLoopAnswer(int u, int pre, int cur)
{
ans += seg.query(len - cur);
for(auto v : nd[u].edg) if(v != pre) getLoopAnswer(v, u, cur + 1);
}
void getLoopAnswer(int u, int cur)
{
seg.modify(nd[u].len, -1);
for(auto v : nd[u].edg) if(v != nd[u].nxt && v != nd[u].lst) getOutsideSize(v, u, nd[u].len + 1, -1);
ans += seg.query(len - cur);
for(auto v : nd[u].edg) if(v != nd[u].nxt && v != nd[u].lst) getLoopAnswer(v, u, cur + 1);
if(~ nd[u].nxt) getLoopAnswer(nd[u].nxt, cur + 1);
}
inline void workOnLoop()
{
getLoop(lp[0], -1);
seg.clear();
getOutsideSize(lp[1], 1);
getLoopAnswer(lp[0], 1);
}
}T;
int main()
{ #ifndef ONLINE_JUDGE freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout); #endif using namespace Zeonfai;
n = getInt(), m = getInt(), len = getInt();
st.initialize();
for(int i = 0, u, v; i < m; ++ i) u = getInt(), v = getInt(), T.addEdge(u, v);
T.work();
if(n == m) T.workOnLoop();
printf("%lld\n", ans);
}

XSY 1749 tree的更多相关文章

  1. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  2. SAP CRM 树视图(TREE VIEW)

    树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...

  3. 无限分级和tree结构数据增删改【提供Demo下载】

    无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...

  4. 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...

  5. Leetcode 笔记 110 - Balanced Binary Tree

    题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...

  6. Leetcode 笔记 100 - Same Tree

    题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...

  7. Leetcode 笔记 99 - Recover Binary Search Tree

    题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...

  8. Leetcode 笔记 98 - Validate Binary Search Tree

    题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...

  9. Leetcode 笔记 101 - Symmetric Tree

    题目链接:Symmetric Tree | LeetCode OJ Given a binary tree, check whether it is a mirror of itself (ie, s ...

随机推荐

  1. 图学java基础篇之集合

    (本文部分图片引用自其他博客,最后有链接,侵删.由于笔记使用markdown记录,格式可能不是太好看,见谅) 集合结构 红字为java.util包下的,绿字为concurrent包下扩展的与并发相关的 ...

  2. 3 View - Response对象

    1. HttpResponse对象:返回数据 from django.http import HttpResponse 在django.http模块中定义了HttpResponse对象的API Htt ...

  3. 线段树[To be continued]

    目录 数据结构--线段树 一.定义 二.性质 三.基本操作 0.结构体 1.建树 2.单点查询 3.单点修改 4.区间修改 5.区间查询 四.题目 单点修改.区域查询模板 五.鸣谢 学姐的Blog 百 ...

  4. leetcode 【 Best Time to Buy and Sell Stock III 】python 实现

    题目: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...

  5. BugKu 2B+基于python的opencv的安装-------CTF 盲水印的套路

    BugKu杂项-2B 下载图片后,binwalk下跑一跑,发现有个zip,分离. 值得一提的是,这个zip是伪加密的. 但是你在分离的时候,伪加密的图片也给你分离出来了.这两个图片2B和B2肉眼看起来 ...

  6. xss games20关小游戏附源代码

    1. get方式的的值直接输出来了. ?name=<script>alert(1)</script> 2. 同样没有过滤,不过需要闭合前边的双引号和>. "&g ...

  7. PAT1022

    输入两个非负10进制整数A和B(<=230-1),输出A+B的D (1 < D <= 10)进制数. 输入格式: 输入在一行中依次给出3个整数A.B和D. 输出格式: 输出A+B的D ...

  8. EasyUi DataGrid 获取选中行的checkbox

    EasyUi DataGrid 获取选中行的checkbox var checked = $(":checkbox[name=ID]:checked"); console.log( ...

  9. arp_ignore和arp_announce内核参数

    arp_announce : INTEGER 对网络接口上本地IP地址发出的ARP报文作出相应级别的限制. 0:本机所有IP地址都向任何一个接口通告ARP报文. 1:尽量仅向该网卡回应与该网段匹配的A ...

  10. eclipse快捷键补全

    Eclipse中 补全快捷键 默认Alt+/ 但是每个人习惯有所不同 我需要来修改自己熟悉的快捷键 windows->preferences->General->keys将Conte ...