(dfs序+莫隊算法/啓發式合併/樹分治)Codeforces 375D - Tree and Queries

題意:ios

一顆根爲1的樹,每一個節點有一個顏色,如今有十萬次查詢,問x的子樹中數量超過k的顏色個數有幾個。算法

分析:ide

一開始想了一下,朦朦朧朧的以爲dfs一下應該能夠作,可是也只是朦朦朧朧,並不知道怎麼下手。優化

百度了一下,「好題中的好題」,4解。spa

 

對於前兩種方法,依賴於dfs序。指針

具體的能夠自行百度,很是巧妙的東西。code

至於莫隊,首先莫隊是個離線算法,用分塊搞一下。blog

對全部查詢排個序,而後不斷移動兩個指針維護信息便可,證實貌似是用曼哈頓距離生成樹。有興趣能夠看看。string

其實,整個過程頗有滑動窗口的味道, 安排好全部查詢的順序,從左往右滑,不夠就補信息,多了就刪信息,雖然確定會有浪費不少信息,不過根號複雜度也無所謂了。it

 

後兩種作法其實就是暴力的優化。

對於暴力,咱們很天然的想法是每一個節點存一個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\n", 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\n", 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\n", 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
相關文章
相關標籤/搜索