【BZOJ 1023】[SHOI2008]cactus仙人掌图
【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1023
【题意】
【题解】
如果不考虑有环的情况;
那么有一个经典的求树的直径的方法;
首先;
树的直径的两端的端点必然都在树的叶子上(或在根节点,考虑一条链的情况);
则
设f[i][0]表示离i这个点最远的叶子节点的距离
f[i][1]表示离i这个点第二远的叶子节点的距离
更新的话
f[x][0]=max(f[son][0]+1);
f[x][1] = max(second(f[son][0])+1);
则可以通过dp求出来所有的节点的f值,取max{f[i][0]+f[i][1]}就是它的直径了;
这里我们可以降成一维的即
ans = max(ans,f[x]+f[son]+1),f[x]=max(f[son]+1);
这里f[x]=max(f[son]+1)在ans更新完后才更新;
这个做法就等同于上面那个做法;
然后该题的情况就是多了一个环;
环的话只要通过环上的非最高点对(x,y);
用f(x)+f(y)+dist(x,y)来更新答案ans;
设环上的最高点为u;
然后用非最高点x的f[x]+dist(x,u)来更新f[x]即可;
挺自然的一个做法吧;
这里的
f(x)+f(y)+dist(x,y)
可以写成
f[x]+f[y]+x-y
这里的x和y是把环破成直线之后x和y在直线上的下标;
x>y
则我们只要维护f[y]-y不下降就可以了
用单调队列搞;
然后因为是最短距离;
所以f[y]-y必须要满足x-y< n/2
这里的n是这个环的长度;
也因为是最短距离;
所以你要把直线的长度延伸到2*n,不然可能会漏解.
【完整代码】
#include <bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define LL long long #define rep1(i,a,b) for (int i = a;i <= b;i++) #define rep2(i,a,b) for (int i = a;i >= b;i--) #define mp make_pair #define pb push_back #define fi first #define se second #define rei(x) scanf("%d",&x) #define rel(x) scanf("%lld",&x) #define ref(x) scanf("%lf",&x) typedef pair<int, int> pii; typedef pair<LL, LL> pll; const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 }; const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 }; const double pi = acos(-1.0); const int N = 5e4+100; int n, m,k,a[N*2],dfn ,low ,num,father ,f ,dep ,ans,q[2*N]; vector <int> g ; void input_data() { rei(n), rei(m); rep1(i, 1, m) { rei(k); rep1(j, 1, k) rei(a[j]); rep1(j, 1, k - 1) g[a[j]].push_back(a[j + 1]), g[a[j + 1]].push_back(a[j]); } } void dp(int root, int x) { int n = dep[x] - dep[root] + 1; for (int i = x; i != root; i = father[i]) a[n--] = f[i]; a = f[root], n = dep[x] - dep[root] + 1; rep1(i, n + 1, 2 * n) a[i] = a[i - n]; int h = 1, t = 1; q[h] = 1; rep1(i, 2, n + n / 2) { while (h <= t && i - q[h] > n / 2) h++; ans = max(ans, a[i] + a[q[h]] + i - q[h]); while (h <= t && a[q[h]] - q[h] <= a[i] - i) t--; q[++t] = i; } rep1(i, 2, n) f[root] = max(f[root], a[i] + min(i - 1, n - i + 1)); } void Tarjan(int x) { dfn[x] = low[x] = ++num; int len = g[x].size(); rep1(i, 0, len - 1) { int y = g[x][i]; if (y == father[x]) continue; if (dfn[y] == 0) dep[y] = dep[x] + 1, father[y] = x, Tarjan(y); low[x] = min(low[x], low[y]); if (dfn[x] < low[y]) ans = max(ans, f[x] + f[y] + 1), f[x] = max(f[x], f[y] + 1); } rep1(i, 0, len - 1) { int y = g[x][i]; if (y!=father[x] && father[y] != x && dfn[x] < dfn[y]) dp(x, y); } } int main() { //freopen("F:\\rush.txt", "r", stdin); input_data(); Tarjan(1); printf("%d\n", ans); //printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC); return 0; }
- BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)
- bzoj1023: [SHOI2008]cactus仙人掌图
- bzoj1023 [SHOI2008]cactus仙人掌图(仙人掌dp+单调队列)
- BZOJ 1023 [SHOI2008]cactus仙人掌图
- bzoj1023: [SHOI2008]cactus仙人掌图
- 【BZOJ 1023】 [SHOI2008]cactus仙人掌图
- BZOJ 1023: [SHOI2008]cactus仙人掌图
- bzoj1023 [SHOI2008]cactus仙人掌图
- 【BZOJ】【1023】【SHOI2008】cactus仙人掌图
- bzoj 1023 [SHOI2008]cactus仙人掌图
- 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)
- 【DP】 BZOJ 1023: [SHOI2008]cactus仙人掌图
- 【BZOJ 1023】【SHOI 2008】cactus仙人掌图
- [bzoj1023][SHOI2008]cactus仙人掌图
- BZOJ1023[SHOI2008]cactus仙人掌图 【仙人掌DP】
- [bzoj1023][SHOI2008]cactus 仙人掌图 (动态规划)
- BZOJ 1023: [SHOI2008]cactus仙人掌图(仙人掌DP)
- bzoj 1023: [SHOI2008]cactus仙人掌图
- BZOJ 1023 SHOI2008 cactus仙人掌图 仙人掌DP
- bzoj千题计划224:bzoj1023: [SHOI2008]cactus仙人掌图