• (dfs序+莫队算法/启发式合并/树分治)Codeforces 375D


    题意:

    一颗根为1的树,每个节点有一个颜色,现在有十万次查询,问x的子树中数量超过k的颜色个数有几个。

    分析:

    一开始想了一下,朦朦胧胧的觉得dfs一下应该可以做,但是也只是朦朦胧胧,并不知道怎么下手。

    百度了一下,“好题中的好题”,4解。

    对于前两种方法,依赖于dfs序。

    具体的可以自行百度,非常巧妙的东西。

    至于莫队,首先莫队是个离线算法,用分块搞一下。

    对所有查询排个序,然后不断移动两个指针维护信息即可,证明貌似是用曼哈顿距离生成树。有兴趣可以看看。

    其实,整个过程很有滑动窗口的味道, 安排好所有查询的顺序,从左往右滑,不够就补信息,多了就删信息,虽然肯定会有浪费很多信息,不过根号复杂度也无所谓了。

    后两种做法其实就是暴力的优化。

    对于暴力,我们很自然的想法是每个节点存一个map,记录此子树的所有颜色个数,父亲的map由儿子的map合并而成。

    至于维护答案,用一个可以查询Rank的平衡树即可,每次产生一个新的map值,就删掉存在Treap中旧的数量,然后添加新的。

    对于启发式合并,上面讲的还不是关键,最关键的是“启发式”这三个字,即每次把小的map并到大的map中。

    否则复杂度无法到达nlogn,又由于Treap的内容在跟随变化,整体复杂度为nlognlogn

    最后一种方法,是最巧妙的,但正如上面说的,其实就是最暴力的优化。

    我们将询问按x分类,对于每个节点进行暴力,那么最坏情况的复杂度显然是n^2。

    然而其实,我们其实可以将子树的一部分信息保留到上一层父亲,最优秀的必然是将最大的子树保留给父亲。

    所以利用dfs回溯的性质,对于每个节点,都会有1棵最大的子树不需要计算。

    整体复杂度为nlogn,虽然我不会证明,不过凭感觉应该差不多。

    代码:

    dfs序+莫队算法:

      1 #include <set>
      2 #include <map>
      3 #include <list>
      4 #include <cmath>
      5 #include <queue>
      6 #include <vector>
      7 #include <bitset>
      8 #include <string>
      9 #include <cctype>
     10 #include <cstdio>
     11 #include <cstring>
     12 #include <cstdlib>
     13 #include <iostream>
     14 #include <algorithm>
     15 
     16 using namespace std;
     17 
     18 typedef long long ll;
     19 typedef unsigned long long ull;
     20 typedef pair<int, int> pii;
     21 #define inf (0x3f3f3f3f)
     22 #define lnf (0x3f3f3f3f3f3f3f3f)
     23 #define eps (1e-6)
     24 #define fi first
     25 #define se second
     26 #define ls (n<<1)
     27 #define rs (n<<1|1)
     28 int sgn(double a) {
     29     return a < -eps ? -1 : a < eps ? 0 : 1;
     30 }
     31 
     32 //--------------------------
     33 
     34 const int maxn = 100010;
     35 const int mod = 1e9 + 7;
     36 
     37 
     38 int n, q;
     39 int col[maxn];
     40 int L[maxn];
     41 int R[maxn];
     42 int d[maxn];
     43 int tot = 0;
     44 vector<int> g[maxn];
     45 struct Q {
     46     int l, r, k, index;
     47 } query[maxn];
     48 int ans[maxn];
     49 int suf[maxn];
     50 int color[maxn];
     51 int cs[maxn];
     52 int bks;
     53 
     54 bool cmp(Q a, Q b) {
     55     if (a.l / bks == b.l / bks)return a.r < b.r;
     56     else return a.l / bks < b.l / bks;
     57 }
     58 
     59 void dfs(int u, int fa, int dep) {
     60     L[u] = ++tot;
     61     color[tot] = col[u];
     62     d[u] = dep;
     63     for (int i = 0; i < g[u].size(); i++) {
     64         int v = g[u][i];
     65         if (v == fa)continue;
     66         dfs(v, u, dep + 1);
     67     }
     68     R[u] = tot;
     69 }
     70 
     71 void solve() {
     72     scanf("%d%d", &n, &q);
     73     bks = (int)sqrt(n);
     74     for (int i = 1; i <= n; i++) {
     75         scanf("%d", &col[i]);
     76     }
     77     for (int i = 0; i < n - 1; i++) {
     78         int u, v;
     79         scanf("%d%d", &u, &v);
     80         g[u].push_back(v);
     81         g[v].push_back(u);
     82     }
     83     dfs(1, -1, 0);
     84     int v;
     85     for (int i = 0; i < q; i++) {
     86         scanf("%d%d", &v, &query[i].k);
     87         query[i].l = L[v];
     88         query[i].r = R[v];
     89         query[i].index = i;
     90     }
     91     sort(query, query + q, cmp);
     92     int pl = 1, pr = 0;
     93     for (int i = 0; i < q; i++) {
     94         int index = query[i].index;
     95         if (query[i].l == query[i].r) {
     96             ans[index] = query[i].k > 1 ? 0 : 1;
     97             continue;
     98         }
     99         if (pr < query[i].r) {
    100             for (int j = pr + 1; j <= query[i].r; j++) {
    101                 suf[++cs[color[j]]]++;
    102             }
    103 
    104         } else {
    105             for (int j = pr; j > query[i].r; j--) {
    106                 suf[cs[color[j]]--]--;
    107             }
    108         }
    109         pr = query[i].r;
    110         if (pl < query[i].l) {
    111             for (int j = pl; j < query[i].l; j++) {
    112                 suf[cs[color[j]]--]--;
    113             }
    114         } else {
    115             for (int j = pl - 1; j >= query[i].l; j--) {
    116                 suf[++cs[color[j]]]++;
    117             }
    118         }
    119         pl = query[i].l;
    120         ans[index] = suf[query[i].k];
    121     }
    122     for (int i = 0; i < q; i++) {
    123         printf("%d
    ", ans[i] );
    124     }
    125 }
    126 
    127 
    128 int main() {
    129 
    130 #ifndef ONLINE_JUDGE
    131     freopen("1.in", "r", stdin);
    132     // freopen("1.out", "w", stdout);
    133 #endif
    134     //iostream::sync_with_stdio(false);
    135     solve();
    136     return 0;
    137 }
    View Code

    启发式合并:

      1 #include <set>
      2 #include <map>
      3 #include <list>
      4 #include <cmath>
      5 #include <queue>
      6 #include <vector>
      7 #include <bitset>
      8 #include <string>
      9 #include <cctype>
     10 #include <cstdio>
     11 #include <cstring>
     12 #include <cstdlib>
     13 #include <iostream>
     14 #include <algorithm>
     15 #include <unordered_map>
     16 
     17 using namespace std;
     18 
     19 typedef long long ll;
     20 typedef unsigned long long ull;
     21 typedef pair<int, int> pii;
     22 #define inf (0x3f3f3f3f)
     23 #define lnf (0x3f3f3f3f3f3f3f3f)
     24 #define eps (1e-6)
     25 #define fi first
     26 #define se second
     27 #define ls (n<<1)
     28 #define rs (n<<1|1)
     29 int sgn(double a) {
     30     return a < -eps ? -1 : a < eps ? 0 : 1;
     31 }
     32 
     33 //--------------------------
     34 
     35 const int maxn = 100010;
     36 const int mod = 1e9 + 7;
     37 
     38 
     39 int n, q;
     40 int col[maxn];
     41 vector<int> g[maxn];
     42 vector<pii> query[maxn];
     43 unordered_map<int, int > color[maxn];
     44 int ans[maxn];
     45 struct Node {
     46     Node *son[2];
     47     int Key, w, Size;
     48     Node(int a, int b, int c, Node *d): Key(a), w(b), Size(c) {
     49         son[0] = son[1] = d;
     50     }
     51 }*__root[maxn], *null;
     52 void init() {
     53     null = new Node(-inf, inf, 0, 0); //这里维护的是小根堆
     54     for (int i = 1; i <= n; i++) {
     55         __root[i] = null = null->son[0] = null->son[1] = null;
     56 
     57     }
     58 }
     59 inline void Rotate(Node *&p, bool b) { //Rotate(p,0)表示;左旋Rotate(p,1)表示右旋
     60     Node *u = p->son[!b];
     61     p->son[!b] = u->son[b];
     62     u->son[b] = p;
     63     u->Size = p->Size;
     64     p->Size = p->son[0]->Size + p->son[1]->Size + 1;
     65     p = u;
     66 }
     67 void Insert(Node *&p, const int &x) { //注意引用
     68     if (p == null) { //如果找到了位置就插入
     69         p = new Node(x, rand(), 1, null);
     70         return;
     71     }
     72     bool b = (x > p->Key); //判断是往左子树还是右子树插入
     73     Insert(p->son[b], x);
     74     p->Size++;  //维护Size
     75     if (p->son[b]->w < p->w) Rotate(p, !b); //在左子树就右旋,在右子树就左旋
     76 }
     77 void Delete(Node *&p, const int &x) {
     78     if (p->son[0] == null && p->son[1] == null) {
     79         p = null; //这里是等到目标结点变为叶子才删除,仅比常规的删除多做了一次旋转,但代码短多了
     80         return;
     81     }
     82     bool b;  //这里的b为if语句后的操作提供了便利
     83     if (p->Key == x) {
     84         b = (p->son[1]->w > p->son[0]->w);
     85         Rotate(p, b);
     86     }  else b = (x > p->Key);
     87     p->Size--;
     88     Delete(p->son[b], x);
     89 }
     90 int Rank(int x, int index) { //返回x的排名(第几小)
     91     Node *p = __root[index];
     92     int Count = 0;
     93     for (; p != null; )
     94         if (p->Key < x) {
     95             Count += p->son[0]->Size + 1;
     96             p = p->son[1];
     97         }  else p = p->son[0];
     98     return Count + 1;
     99 }
    100 
    101 bool Find(int x, int index) {
    102     Node *p = __root[index];
    103     for (; p != null;) {
    104         if (p->Key < x)p = p->son[1];
    105         else if (p->Key > x)p = p->son[0];
    106         else return true;
    107     }
    108     return false;
    109 }
    110 
    111 void dfs(int u, int fa) {
    112     if (Find(color[u][col[u]], u))Delete(__root[u], color[u][col[u]]);
    113     color[u][col[u]]++;
    114     Insert(__root[u], color[u][col[u]]);
    115     for (int i = 0; i < g[u].size(); i++) {
    116         int v = g[u][i];
    117         if (v == fa)continue;
    118         dfs(v, u);
    119         if (color[u].size() < color[v].size()) {
    120             swap(color[u], color[v]);
    121             swap(__root[u], __root[v]);
    122         }
    123         for (unordered_map<int, int >::iterator it = color[v].begin(); it != color[v].end(); it++) {
    124             if (Find(color[u][it->fi], u))Delete(__root[u], color[u][it->fi]);
    125             color[u][it->fi] += it->se;
    126             Insert(__root[u], color[u][it->fi]);
    127         }
    128     }
    129     for (int i = 0; i < query[u].size(); i++) {
    130         ans[query[u][i].se] = __root[u]->Size - Rank(query[u][i].fi, u) + 1;
    131     }
    132 
    133 }
    134 
    135 void solve() {
    136     scanf("%d%d", &n, &q);
    137     init();
    138     for (int i = 1; i <= n; i++) {
    139         scanf("%d", &col[i]);
    140     }
    141     for (int i = 0; i < n - 1; i++) {
    142         int u, v;
    143         scanf("%d%d", &u, &v);
    144         g[u].push_back(v);
    145         g[v].push_back(u);
    146     }
    147     for (int i = 0; i < q; i++) {
    148         int v, k;
    149         scanf("%d%d", &v, &k);
    150         query[v].push_back(make_pair(k, i));
    151     }
    152     dfs(1, -1);
    153     for (int i = 0; i < q; i++) {
    154         printf("%d
    ", ans[i] );
    155     }
    156 
    157 
    158 }
    159 
    160 
    161 int main() {
    162 
    163 #ifndef ONLINE_JUDGE
    164     freopen("1.in", "r", stdin);
    165     // freopen("1.out", "w", stdout);
    166 #endif
    167     //iostream::sync_with_stdio(false);
    168     solve();
    169     return 0;
    170 }
    View Code

    分治:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<cstring>
      6 #include<set>
      7 #include<vector>
      8 #include<queue>
      9 #include<map>
     10 #include<list>
     11 #include<bitset>
     12 #include<string>
     13 #include<cctype>
     14 #include<cstdlib>
     15 
     16 using namespace std;
     17 
     18 typedef long long ll;
     19 typedef unsigned long long ull;
     20 typedef pair<int, int> pii;
     21 #define inf (0x3f3f3f3f)
     22 #define lnf (0x3f3f3f3f3f3f3f3f)
     23 #define fi first
     24 #define se second
     25 #define eps (1e-8)
     26 int sgn(double a) {
     27     return a < -eps ? -1 : a < eps ? 0 : 1;
     28 }
     29 
     30 const int maxn = 100010;
     31 
     32 int n, q;
     33 int col[maxn];
     34 vector<int> g[maxn];
     35 vector<pii> query[maxn];
     36 int sz[maxn];
     37 int cnt[maxn];
     38 int sum[maxn];
     39 int ans[maxn];
     40 bool big[maxn];
     41 int tot = 0;
     42 
     43 void dfs1(int u, int fa) {
     44     sz[u] = 1;
     45     for (int i = 0; i < g[u].size(); i++) {
     46         int v = g[u][i];
     47         if (v == fa)continue;
     48         dfs1(v, u);
     49         sz[u] += sz[v];
     50     }
     51 }
     52 
     53 void add(int v, int p, int x) {
     54     if(x == 1) {
     55         sum[++cnt[col[v]]]++;
     56     } else {
     57         sum[cnt[col[v]]--]--;
     58     }
     59     for(auto u : g[v])
     60         if(u != p && !big[u]) {
     61             add(u, v, x);
     62         }
     63 }
     64 
     65 void dfs(int v, int p, bool keep) {
     66     int mx = -1, bigChild = -1;
     67     for(auto u : g[v])
     68         if(u != p && sz[u] > mx)
     69             mx = sz[u], bigChild = u;
     70     for(auto u : g[v])
     71         if(u != p && u != bigChild)
     72             dfs(u, v, 0); 
     73     if(bigChild != -1)
     74         dfs(bigChild, v, 1), big[bigChild] = 1; 
     75     add(v, p, 1);
     76     for (int i = 0; i < query[v].size(); i++) {
     77         ans[query[v][i].se] = sum[query[v][i].fi];
     78     }
     79     if(bigChild != -1)
     80         big[bigChild] = 0;
     81     if(keep == 0)
     82         add(v, p, -1);
     83 }
     84 
     85 void solve() {
     86     scanf("%d%d", &n, &q);
     87     for (int i = 1; i <= n; i++) {
     88         scanf("%d", &col[i]);
     89     }
     90     for (int i = 0; i < n - 1; i++) {
     91         int u, v;
     92         scanf("%d%d", &u, &v);
     93         g[u].push_back(v);
     94         g[v].push_back(u);
     95     }
     96     for (int i = 0; i < q; i++) {
     97         int v, k;
     98         scanf("%d%d", &v, &k);
     99         query[v].push_back(make_pair(k, i));
    100     }
    101     dfs1(1, -1);
    102     dfs(1, -1, false);
    103     for (int i = 0; i < q; i++) {
    104         printf("%d
    ", ans[i] );
    105     }
    106 
    107 
    108 }
    109 
    110 int main() {
    111 
    112 #ifndef ONLINE_JUDGE
    113     freopen("1.in", "r", stdin);
    114     //freopen("1.out", "w", stdout);
    115 #endif
    116     //iostream::sync_with_stdio(false);
    117     solve();
    118     return 0;
    119 }
    View Code
  • 相关阅读:
    升讯威微信营销系统开发实践:目录
    升讯威微信营销系统开发实践:订阅号和服务号深入分析( 完整开源于 Github)
    ASP.NET MVC (Razor)开发<<周报与绩效考核系统>>,并免费提供园友们使用~~~
    使用 SailingEase WinForm 框架构建复合式应用程序(插件式应用程序)
    vertica提取json字段值
    centos上配置redis从节点
    查看出网IP
    centos上tcp抓包
    修改centos服务器时区并同步最新时间
    解决centos下tomcat启动太慢 & JDBC连接oracle太慢的问题
  • 原文地址:https://www.cnblogs.com/tak-fate/p/7000661.html
Copyright © 2020-2023  润新知