树的直径

题单介绍

## ST表 给定静态数组,多次查询区间最值 预处理复杂度O(nlogn) 单次查询O(1) ```cpp int mx[100005][21]; // mx[i][j]表示从i开始数2^j个元素中的最大值 // mx[3][2] = max{a[3],a[4],a[5],a[6]} // mx[i][j] = max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); // 在任何倍增问题里,如果担心越界,最好的方法是不处理 int query(int l,int r){ int k = log2(r-l+1); // log2有一定常数 return max(mx[l][k],mx[r-(1<<k)+1][k]); } int main(){ for(int i=1;i<=n;i++) mx[i][0] = a[i]; for(int j=1;j<=20;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ mx[i][j] = max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); } } } ``` ## 离散化 ```cpp for(int i=1;i<=n;i++) b[i] = a[i]; sort(b+1,b+n+1); // b : 1,1,2,200,300,300,400 // 1. map map<int,int>mp; int len = unique(b+1,b+n+1) - b - 1; for(int i=1;i<=len;i++) mp[b[i]] = i; // 2. lower_bound // b : 1,1,2,200,300,300,400 int len = unique(b+1,b+n+1) - b - 1; for(int i=1;i<=n;i++) a[i] = lower_bound(b+1,b+len+1,a[i])-b; ``` ## set 维护集合(一些独立的数值) ```cpp set<int>s; // 数学中的集合是没有重复元素 s.insert(10); // 插入 s.insert(10); // 插入重复数字无效 cout << s.size(); s.erase(10); // 删除数字10 cout << *s.begin(); // set内部是有序的 begin就是最小值 --end()是最大值 cout << *--s.end(); cout << *s.rbegin(); // rbegin反向迭代器 // 输出次大值 cout << *prev(s.end(),2); // 输出次小值 cout << *next(s.begin()); // 找到第一个大于等于10的位置 s.lower_bound(10); multiset<int>ms; // 可重集合 {10,10,20} ms.insert(10); ms.insert(10); ms.insert(20); ms.erase(10); // 删掉里面所有的10 ms.erase(ms.lower_bound(10)); // 传入的是第一个10的位置 cout << ms.count(10); ``` ## pair ```cpp #define pii pair<int,int> // 但凡需要两个参数的结构体 不妨换成pair // .first .second vector<pii> a; a.push_back({1,3}); a.push_back({2,5}); a.push_back({3,1}); a.push_back({4,10}); sort(a.begin(),a.end()); // pair类型是有默认的比较规则的 // 想把一些数值排序,同时记录他们原本的下标位置 // pair<数值,下标> 直接排序 可以把想排序的东西放在first的位置 // dijkstra priority_queue <pii> pq; memset(dis,0x3f,sizeof(dis)); dis[s] = 0; pq.push({s,0}); for(int i=1;i<=n;i++){ auto cur = pq.top(); int nowdis = -cur.first; int id = cur.second; for(int j=0;j<e[id].size();j++){ int to = e[id][j].first; int len = e[id][j].second; if(nowdis + len < dis[to]){ dis[to] = nowdis + len; pq.push({-dis[to],to}); } } } // map内部存储 若干个pair组成的 map也是默认有序的 map<int,int> mp; mp[2] = 4; mp[4] = 3; // (2,4) (4,3) for(auto it=mp.begin();it!=mp.end();it++){ cout << it->first << ' ' << it->second; } for(auto it:mp){ // 这里的it直接是每一项的数值 cout << it.first << ' ' << it.second; } ``` ## 树的基础 - 树上dfs - 树的直径 - 性质1:所有的直径中点重合 - 性质2:对于树上的任意点x,距离x最远的点一定是某条直径的端点 - 随便找到一条直径(p,q) 那么对于x的最远距离要么是dis(x,p) 要么是dis(x,q) - 树的重心 ```cpp vector<int>E[maxn]; // 维护一些额外的信息 dep[x],sz[x] void dfs(int x,int f){ sz[x] = 1; dep[x] = dep[f] + 1; for(auto y:E[x]){ if(y == f) continue; dfs(y,x); sz[x] += sz[y]; } } ```

题目列表

  • 树的直径
  • [SDOI2013] 直径
  • Civilization
  • [NOI2003] 逃学的小孩 / 数据生成器
  • [NOIP 2007 提高组] 树网的核
  • [APIO2010] 巡逻
  • [ABC221F] Diameter set
  • [ABC222F] Expensive Expense