【2016东北四省赛】
题意:给出一个R*C(R, C <= 1e9)的地图,地图上有n(n <= 200)个点的障碍,其余为空地。问有多少个四连通图以及各个四连通图的大小。
题解:离散化。将x, y坐标分别离散化。对于xi点再插入xi-1, xi+1两个点。
则离散化后的权值大小为xi-xi-1.对y作同样处理。处理完毕后bfs图,空白格的面积为x对应权值与y对应权值之积。
Time: 0ms
1 #include <bits/stdc++.h> 2 #define ll long long 3 #define gg puts("gg"); 4 using namespace std; 5 int ma[666][666]; 6 int xma[666], yma[666]; 7 int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}, X, Y; 8 void dfs(int x, int y, ll& ret){ 9 if(!ma[x][y]){ 10 ret += xma[x]*(ll)yma[y]; 11 ma[x][y] = 1; 12 for(int i = 0; i < 4; i++){ 13 int xi = x+dx[i], yi = y+dy[i]; 14 dfs(xi, yi, ret); 15 } 16 } 17 } 18 int x[222], y[222]; 19 20 int main(){ 21 int t, ca = 1; scanf("%d", &t); 22 while(t--){ 23 printf("Case #%d:\n", ca++); 24 int r, c, n; scanf("%d%d", &r, &c); 25 scanf("%d", &n); 26 vector<int> xx, yy; 27 xx.push_back(0), xx.push_back(r), xx.push_back(r+1); 28 yy.push_back(0), yy.push_back(c), yy.push_back(c+1); 29 for(int i = 0; i < n; i++){ 30 scanf("%d%d", x+i, y+i); 31 for(int j = -1; j <= 1; j++) 32 xx.push_back(x[i]+j), yy.push_back(y[i]+j); 33 } 34 sort(xx.begin(), xx.end()); 35 xx.erase(unique(xx.begin(), xx.end()), xx.end()); 36 xma[0] = 1; 37 for(int i = 1; i < xx.size(); i++) 38 xma[i] = xx[i]-xx[i-1]; 39 sort(yy.begin(), yy.end()); 40 yy.erase(unique(yy.begin(), yy.end()), yy.end()); 41 yma[0] = 1; 42 for(int i = 1; i < yy.size(); i++) 43 yma[i] = yy[i]-yy[i-1]; 44 45 memset(ma, 0, sizeof(ma)); 46 for(int i = 0; i < n; i++){ 47 int a = lower_bound(xx.begin(), xx.end(), x[i])-xx.begin(); 48 int b = lower_bound(yy.begin(), yy.end(), y[i])-yy.begin(); 49 ma[a][b] = 1; 50 } 51 int rr = xx.size(), cc = yy.size(); 52 for(int i = 0; i < cc; i++) 53 ma[0][i] = ma[rr-1][i] = 1; 54 for(int i = 0; i < rr; i++) 55 ma[i][0] = ma[i][cc-1] = 1; 56 57 vector<ll> ans; 58 for(int i = 1; i < rr; i++) 59 for(int j = 1; j < cc; j++) 60 if(!ma[i][j]) { 61 ll ret = 0; 62 dfs(i, j, ret); 63 ans.push_back(ret); 64 } 65 sort(ans.begin(), ans.end()); 66 int tot = ans.size(); 67 printf("%d\n", tot); 68 for(int i = 0; i < tot; i++) 69 printf("%lld%c", ans[i], " \n"[i == tot-1]); 70 } 71 return 0; 72 }
********************************************************************
题意:给出一个根节点为1的树(n <= 100000),树中的结点分为重要结点与不重要结点。
有q个询问,每次询问给出一个不重要结点的集合(m <= 100000), 统计一类点(它是重要结点 或者 它是两个重要结点的最近公共祖先) 的总数。
题解:
1372MS: dfs, 子结点不是集合中的点时直接return,否则递归dfs.
Time: 1372MS
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5+10; 4 vector<int> ve[N]; 5 int fa[N], n, m, ans; 6 int temp[N], vis[N]; 7 int dfs(int f, int x){ 8 fa[x] = f; 9 for(int i = 0; i < ve[x].size(); i++){ 10 int y = ve[x][i]; 11 if(y == f) continue ; 12 dfs(x, y); 13 } 14 } 15 int dfs2(int f, int x, int pos){ 16 int num = 0; 17 for(int i = 0; i < ve[x].size()&&num < 2; i++){ 18 int y = ve[x][i]; 19 if(y == f) continue ; 20 int ppos = lower_bound(temp, temp+m, y)-temp; 21 if(ppos >= m||temp[ppos] != y||vis[ppos] > 0) num++; 22 else if(vis[ppos] == -1&&dfs2(x, y, ppos) > 0) 23 num++; 24 } 25 if(num > 1) ans++; 26 return vis[pos] = num; 27 } 28 29 int main(){ 30 int t, ca = 1; scanf("%d", &t); 31 while(t--){ 32 int q, u, v; scanf("%d%d", &n, &q); 33 for(int i = 1; i < n; i++){ 34 scanf("%d%d", &u, &v); 35 ve[u].push_back(v); 36 ve[v].push_back(u); 37 } 38 dfs(0, 1); 39 printf("Case #%d:\n", ca++); 40 while(q--){ 41 scanf("%d", &m); 42 for(int i = 0; i < m; i++) 43 scanf("%d", temp+i); 44 sort(temp, temp+m); 45 memset(vis, -1, sizeof(int)*(m+1)); 46 ans = 0; 47 for(int i = 0; i < m; i++) if(vis[i] == -1) 48 dfs2(fa[temp[i]], temp[i], i); 49 printf("%d\n", n-m+ans); 50 } 51 for(int i = 1; i <= n; i++) 52 ve[i].clear(); 53 } 54 return 0; 55 }
1794MS: 维护一个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 }
诸神对凡人心生艳羡,厌倦天堂。