標籤:color clear 題解 can 統計 include 東北 case back
HDU5927
題意:給出一個根節點為1的樹(n <= 100000),樹中的結點分為重要結點與不重要結點。
有q個詢問,每次詢問給出一個不重要結點的集合(m <= 100000), 統計一類點(它是重要結點 或者 它是兩個重要結點的最近公用祖先) 的總數。
題解:維護一個set集合表示以該結點為根的子樹不含重要結點,set集合初始即為m個點。按 後序遍曆 將集合中的點排序後(ra表示結點後序遍曆中的排名),對每個點,尋找子結點點,若至少有兩個子結點不在set裡,則該點是可行點,同時將其從集合中刪除。
複雜度分析:每次詢問的複雜度為O(mlogm)
time: 1794MS
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5+10; 4 vector<int> ve[N]; 5 int ra[N], tot; 6 void dfs(int f, int x){ 7 for(int i = 0; i < ve[x].size(); i++){ 8 int y = ve[x][i]; 9 if(y == f) continue ;10 dfs(x, y);11 }12 ra[x] = tot++;13 }14 bool cmp(int a, int b){15 return ra[a] < ra[b];16 }17 18 19 int temp[N];20 int tag[N];21 int main(){22 int t, ca = 1; scanf("%d", &t);23 while(t--){24 int n, q, u, v; scanf("%d%d", &n, &q);25 for(int i = 1; i < n; i++){26 scanf("%d%d", &u, &v);27 ve[u].push_back(v);28 ve[v].push_back(u);29 }30 tot = 0;31 dfs(0, 1);32 printf("Case #%d:\n", ca++);33 while(q--){34 int m, x; scanf("%d", &m);35 for(int i = 0; i < m; i++)36 scanf("%d", temp+i);37 sort(temp, temp+m, cmp);38 set<int> se;39 for(int i = 0; i < m; i++)40 se.insert(temp[i]);41 int ans = 0;42 for(int i = 0; i < m; i++){43 int x = temp[i], sum = 0;44 for(int j = 0; j < ve[x].size(); j++){45 int y = ve[x][j];46 if(ra[y] > ra[x]) continue;47 if(se.find(y) == se.end()){48 sum++;49 if(sum > 1){50 ans++;51 break;52 }53 se.erase(x);54 }55 }56 }57 printf("%d\n", n-m+ans);58 }59 for(int i = 1; i <= n; i++)60 ve[i].clear();61 }62 return 0;63 }
【2016東北四省賽】