zoukankan      html  css  js  c++  java
  • BZOJ1776

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1776

    题目大意:一棵n个点的树,树上每个点属于一个党派,要求每个党派的最远距离点。两点间距离为两点间边的个数。

    主观思路:看到树上两点距离立即想到dep[x] + dep[y] - 2 * dep[lca(x, y)]这件事。于是想到树形序列化的思想,搞成一个中序遍历的dfs序列。序列中每个点有一个dep,也有一个col表示点深度和所属党派,依次枚举dfs序列中的点,对于当前点x它与之前所有同党派y之间的最远距离取决于dep[y] - 2 * min{dep[k], k在dfs序列y,x之间}。这里用了一种类似单调队列的思想可以做到每个点只进队(我对每个党派的点开了一个vector)一次,详见代码,属于乱搞。对于那个min就用rmq提前对dep维护一下即可。

      1 /**************************************************************
      2     Problem: 1776
      3     User: SWUN2015
      4     Language: C++
      5     Result: Accepted
      6     Time:1988 ms
      7     Memory:48060 kb
      8 ****************************************************************/
      9  
     10 #include <cstdio>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <cmath>
     14 #include <vector>
     15 #include <algorithm>
     16 using namespace std;
     17   
     18 const int MaxN = 2 * 1e5, MaxM = 4 * 1e5;
     19 struct ARR
     20 {
     21     int loc, dep, MiN, pre;
     22 };
     23 int n, K, all, Root, tot;
     24 int dep[MaxN + 5], col[MaxN + 5], dfs_seq[MaxN + 5], ans[MaxN + 5];
     25 int p[MaxN + 5], pre[MaxM + 5], last[MaxN + 5], other[MaxM + 5];
     26 int rmq[MaxN + 5][30];
     27 vector <ARR> a[MaxN + 5];
     28   
     29 void Build(int x, int y)
     30 {
     31     pre[++all] = last[x];
     32     last[x] = all;
     33     other[all] = y;
     34 }
     35   
     36 void Init()
     37 {
     38     all = -1; memset(last, -1, sizeof(last));
     39     scanf("%d%d", &n, &K);
     40     for (int i = 1; i <= n; i++)
     41     {
     42         scanf("%d%d", &col[i], &p[i]);
     43         Build(i, p[i]); Build(p[i], i);
     44         if (p[i] == 0) Root = i;
     45     }
     46 }
     47   
     48 void Dfs(int x, int fa, int d)
     49 {
     50     dfs_seq[++tot] = x;
     51     dep[x] = d;
     52     int ed = last[x], dr;
     53     while (ed != -1)
     54     {
     55         dr = other[ed];
     56         if (dr != fa) Dfs(dr, x, d + 1);
     57         ed = pre[ed];
     58     }
     59 }
     60   
     61 void RMQ()
     62 {
     63     int K = (int)(double(log(n)) / double(log(2)));
     64     for (int i = 1; i <= n; i++) rmq[i][0] = dep[dfs_seq[i]];
     65     for (int i = 1; i <= K; i++)
     66         for (int j = 1; j <= n - (1 << i) + 1; j++)
     67             rmq[j][i] = min(rmq[j][i - 1], rmq[j + (1 << (i - 1))][i - 1]);
     68 }
     69   
     70 void Insert(int x)
     71 {
     72     int t, c = col[dfs_seq[x]]; 
     73     if (a[c].size() > 0)
     74     {
     75         t = a[c].size();
     76         int pos, dd = 0;
     77         int l = a[c][--t].loc + 1, r = x;
     78         int K = (int)(double(log(r - l + 1)) / double(log(2)));
     79         int MiN = min(rmq[l][K], rmq[r - (1 << K) + 1][K]);
     80         ARR res;
     81         while (t >= 0 && MiN <= a[c][t].MiN) 
     82         {
     83             if (a[c][t].dep >= dd) dd = a[c][t].dep, pos = a[c][t].loc;
     84             a[c].pop_back(); t--;
     85         }   
     86         res.dep = dd; res.loc = pos; res.MiN = MiN; 
     87         if (t >= 0) res.pre = max(a[c][t].pre, res.dep - 2 * (res.MiN - 1));
     88             else res.pre = res.dep - 2 * (res.MiN - 1);
     89         a[c].push_back(res);
     90         res.dep = dep[dfs_seq[x]]; res.loc = x; res.MiN = 1 << 30; 
     91         res.pre = a[c][t + 1].pre;
     92         a[c].push_back(res);
     93         t += 2;
     94         ans[c] = max(ans[c], a[c][t].pre + dep[dfs_seq[x]]);
     95     }
     96     else
     97     {
     98         t = 0;
     99         ARR res;
    100         res.dep = dep[dfs_seq[x]]; res.loc = x; res.MiN = 1 << 30; res.pre = -(1 << 30);
    101         a[c].push_back(res);
    102     }
    103 }
    104   
    105 void Solve()
    106 {
    107     Dfs(Root, 0, 0); RMQ();
    108     for (int i = 1; i <= n; i++) {Insert(i);}//printf("%d %d
    ", dfs_seq[i], ans[col[dfs_seq[i]]]);}
    109     for (int i = 1; i <= K; i++) printf("%d
    ", ans[i]);
    110 }
    111   
    112 int main()
    113 {
    114     Init();
    115     Solve();
    116 }
    View Code

    于是这道题就成了RMQ预处理之后的O(N)乱搞题,然而看了题解之后异常崩溃。

    有这样一个结论:每个政党中的最远距离点对,必然有一个点是该政党dep最深的点。仔细考虑没有理由反驳…

    于是题目变得很水,找到每个党派的dep最深点,再顺次枚举该党派的所有点,找到lca求值更新答案即可。复杂度O(nlogn)。

  • 相关阅读:
    b_lg_选学霸(并查集+01背包)
    b_lq_小明的魔法(反向思维)
    多测师课堂019_第一个月综合面试题(01) _高级讲师肖sir
    多测师课堂017_项目数据 _高级讲师肖sir
    linux whoami 显示当前用户的用户名
    linux shutdown 命令 关机 重启
    linux reboot 重启命令
    linux基础 目录
    linux uname 命令 打印系统信息
    前端 CSS层叠性 CSS选择器优先级
  • 原文地址:https://www.cnblogs.com/ChopsticksAN/p/5137899.html
Copyright © 2011-2022 走看看