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 ...
随机推荐
- 序列化模块--json模块--pickle模块-shelve模块
什么叫序列化? 序列化是指把内存里的数据类型转变成字符串,以使其能存储到硬盘或通过网络传播到远程,因为硬盘或网络传输时只能接受bytes 例: 把内存数据 转成字符 # data ={# 'roles ...
- Beats、Filebea入门
1. Filebeat配置简介 2. Filebeat收集nginx日志 3. packetbeat简介与演示
- 静态文本框控件的美化CStatic
VC通用控件都是灰色,当对程序界面进行美化时,使用通用控件就和美化后的程序界面不搭配,在VB,C#中,可以很方便的更改控件背景颜色,但在VC中就不能,需要我们自己来完善这方面的功能.我在这只简单的介绍 ...
- diea
http://name.vip.int ellig.top/name
- 【bzoj3916】[Baltic2014]friends 字符串hash
题目描述 有三个好朋友喜欢在一起玩游戏,A君写下一个字符串S,B君将其复制一遍得到T,C君在T的任意位置(包括首尾)插入一个字符得到U.现在你得到了U,请你找出S. 输入 第一行一个数N,表示U的长度 ...
- xml读取 避开并发(xml的一些操作)
很多地方读取文件可能会出现并发现象 处理: 使用FileMode.Open, FileAccess.Read, FileShare.ReadWrite 避开并发 public static List& ...
- [01] radio ,checkbox 表单文字对齐
http://www.cnblogs.com/wangsir015/p/5555818.html 这几天在做表单时总会碰到复选框(checkbox)和单选框(radio)与文字不对齐的问题,要不是ch ...
- cxGrid让指定的某行自动呈选选中的状态
cxView.ViewData.Rows[cxView.DataController.DataSource.DataSet.RecNo-1].Selected := True;//将当前的行呈选中的状 ...
- Codeforces 297C. Splitting the Uniqueness
C. Splitting the Uniqueness time limit per test:1 second memory limit per test:256 megabytes input:s ...
- LOJ#2083. 「NOI2016」优秀的拆分
$n \leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种.$t \leq 10$组询问. $n^3$过80,$n^2$过95,鬼去写正解.. $n^2$:先枚举一次算每个位置 ...