XSY 1749 tree
题目大意
给定一棵基环树, 问你有多少条路径的长度\(\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的更多相关文章
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- SAP CRM 树视图(TREE VIEW)
树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...
- 无限分级和tree结构数据增删改【提供Demo下载】
无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...
- 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...
- Leetcode 笔记 110 - Balanced Binary Tree
题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...
- Leetcode 笔记 100 - Same Tree
题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...
- Leetcode 笔记 99 - Recover Binary Search Tree
题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...
- Leetcode 笔记 98 - Validate Binary Search Tree
题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...
- Leetcode 笔记 101 - Symmetric Tree
题目链接:Symmetric Tree | LeetCode OJ Given a binary tree, check whether it is a mirror of itself (ie, s ...
随机推荐
- error LNK2001: unresolved external symbol ___CxxFrameHandler3
Q: VS2005编译的静态库, 在vc++6.0中连接出现错误 error LNK2001: unresolved external symbol ___CxxFrameHandler3 A: ...
- IOS开发---菜鸟学习之路--(十)-实现新闻详细信息浏览页面
前面已经将了上下拉刷新 实现了上下拉刷新后我们的第一级界面就做好,接下来我们就需要实现 新闻详细信息浏览了 我个人认为一般实现新闻详细页面的方法有两种(主要是数据源的不同导致了方法的不同) 第一种是本 ...
- plsql编程
ORACLE PL/SQL编程详解 SQL语言只是访问.操作数据库的语言,并不是一种具有流程控制的程序设计语言,而只有程序设计语言才能用于应用软件的开发.PL /SQL是一种高级数据库程序设计语言,该 ...
- Python/PHP 远程文件/图片 下载
php 实现远程图片下载并保存到本地 /* *功能:php完美实现下载远程图片保存到本地 *参数:文件url,保存文件目录,保存文件名称,使用的下载方式 *当保存文件名称为空时则使用远程文件原来的名称 ...
- [HTTPS]pfx转jks
keytool -importkeystore -srckeystore src.pfx -srcstoretype pkcs12 -destkeystore trg.jks -deststoret ...
- OAuth 开放授权
什么是OAuth授权? 一.什么是OAuth协议 OAuth(开放授权)是一个开放标准. 允许第三方网站在用户授权的前提下访问在用户在服务商那里存储的各种信息. 而这种授权无需将用户提供用户名和密 ...
- c语言有用函数收集
1 strtok :分解字符串为一组字符串.s为要分解的字符串,delim为分隔符字符串.首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL. 2 strstr :从字符串str1中查找 ...
- 【bzoj3295】[Cqoi2011]动态逆序对 线段树套SBT
题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序 ...
- 【bzoj1408】[Noi2002]Robot 数论+dp
题目描述 输入 输出 样例输入 3 2 1 3 2 5 1 样例输出 8 6 75 题解 语文题+数论+dp 花了大段讲述什么叫mu,什么叫phi,只是新定义的mu将2看作有平方因子,新定义的phi( ...
- 本文将介绍“数据计算”环节中常用的三种分布式计算组件——Hadoop、Storm以及Spark。
本文将介绍“数据计算”环节中常用的三种分布式计算组件——Hadoop.Storm以及Spark. 当前的高性能PC机.中型机等机器在处理海量数据时,其计算能力.内存容量等指标都远远无法达到要求.在大数 ...