#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e5+50; typedef long long ll; ///加边 int cnt, h[maxn]; struct edge { int to, pre, v; } e[maxn << 1]; void init() { cnt = 0; memset(h, 0, sizeof(h)); } void add(int from, int to, int v) { cnt++; e[cnt].pre = h[from]; ///5-->3-->1-->0 e[cnt].to = to; e[cnt].v = v; h[from] = cnt; } ///LCA int dist[maxn]; int dep[maxn]; int anc[maxn][33]; ///2分的父亲节点 void dfs(int u, int fa) { for(int i = h[u]; i; i = e[i].pre) { int v = e[i].to; if(v == fa) continue; dist[v] = dist[u] + e[i].v; dep[v] = dep[u] + 1; anc[v][0] = u; dfs(v, u); } } void LCA_init(int n) { for(int j = 1; (1 << j) < n; j++) for(int i = 1; i <= n; i++) if(anc[i][j-1]) anc[i][j] = anc[anc[i][j-1]][j-1]; } int LCA(int u, int v) { int log; if(dep[u] < dep[v]) swap(u, v); for(log = 0; (1 << log) < dep[u]; log++); for(int i = log; i >= 0; i--) if(dep[u] - (1 << i) >= dep[v]) u = anc[u][i]; if(u == v) return u; for(int i = log; i >= 0; i--) if(anc[u][i] && anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i]; return anc[u][0]; } int w[maxn]; int sum[maxn]; int dfs2(int u, int fa) { sum[u] += w[u]; for(int i = h[u]; i; i = e[i].pre) { int v = e[i].to; if(v == fa) continue; sum[u] += dfs2(v, u); } return sum[u]; } int main() { init(); int n, m; scanf("%d %d", &n, &m); for(int i = 1; i < n; i++) { int u, v; scanf("%d %d", &u, &v); add(u, v, 1), add(v, u, 1); } dfs(1, -1); LCA_init(n); memset(w, 0, sizeof(w)); for(int i = 1; i <= m; i++) { int u, v; scanf("%d %d", &u ,&v); w[u] += 1, w[v] += 1; // printf("%d ", LCA(u, v)); w[LCA(u, v)] += -2; } dfs2(1, -1); /*for(int i = 1; i <= n; i++) { printf("%d ", sum[i]); }*/ int ans = 0; for(int i = 2; i <= n; i++) { if(sum[i] == 0) ans += m; if(sum[i] == 1) ans++; } printf("%d ", ans); return 0; }
各种剪枝。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 50; vector<int> g[maxn]; int in[maxn]; int vis[maxn]; vector<int> ans; void dfs(int u, int fa, int flag) { if(flag == 0) { for(int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if(v == fa) continue; dfs(v, u, 0); } } if(in[u] != 0 && (in[u] % 2 == 0)) { if(!vis[u]) ans.push_back(u), vis[u] = 1; for(int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if(flag == 1 && v == fa) continue; if(in[u] > 0)in[u]--; if(in[v] > 0) { in[v]--; if(in[v] == 0 && (!vis[v])) ans.push_back(v), vis[v] = 1; } if(v == fa) continue; if(in[v] != 0 && (in[v] % 2 == 0)) dfs(v, u, 1); } } } int main() { int n; scanf("%d", &n); int fa = 0; memset(in, 0, sizeof(in)); memset(vis, 0, sizeof(vis)); for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); if(!x) fa = i; else g[x].push_back(i), g[i].push_back(x), in[i]++, in[x]++; } dfs(fa, -1, 0); int cnt = 0; for(int i = 1; i <= n; i++) if(in[i] == 0) cnt++; if(cnt == n) { printf("YES "); for(int i = 0; i < ans.size(); i++) printf("%d ", ans[i]); if(n == 1) printf("1 "); } else printf("NO "); return 0; }
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 50; int pre[maxn * 2]; int x[maxn * 2]; struct node { int l, r, w; friend bool operator < (node A, node B) { if(A.w != B.w)return A.w > B.w; else return A.l < B.l; } }; node cnt[maxn]; int Find(int x) { return x == pre[x] ? x : pre[x] = Find(pre[x]); } void merge1(int x,int y) { pre[Find(x)] = Find(y); } int main() { int T; scanf("%d", &T); while(T--) { for(int i = 0; i < maxn * 2; i++) pre[i] = i; int num = 0; int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d %d %d", &cnt[i].l, &cnt[i].r, &cnt[i].w); x[num++] = cnt[i].l, x[num++] = cnt[i].r; } sort(x, x + num); num = unique(x, x + num) - x; for(int i = 1; i <= n; i++) { cnt[i].l = lower_bound(x, x + num, cnt[i].l) - x; cnt[i].r = lower_bound(x, x + num, cnt[i].r) - x; } sort(cnt + 1, cnt + n + 1); int flag = 0; for(int i = 1; i <= n; i++) { if(cnt[i].w) { merge1(cnt[i].l, cnt[i].r); } else { if(Find(cnt[i].l) == Find(cnt[i].r)) { flag = 1; break; } } } if(flag) printf("NO "); else printf("YES "); } return 0; } /* 2 3 1 2 0 2 3 0 1 3 1 */
优先队列
#include <cstdio> #include <algorithm> #include <queue> #include <vector> using namespace std; priority_queue <int, vector<int>, greater<int> > q; const int maxn = 1e4 + 50; vector<int> pro[maxn]; int main() { int n; while(scanf("%d", &n) != EOF) { for(int i = 1; i < maxn; i++) pro[i].clear(); int p, d; for(int i = 1; i <= n; i++) { scanf("%d %d", &p, &d); pro[d].push_back(p); } for(int i = 1; i <= 10000; i++) sort(pro[i].begin(), pro[i].end()); for(int i = 1; i <= 10000; i++) { int tmp = i; for(int j = pro[i].size() - 1; j >= 0 && tmp >= 1; j--, tmp--) { q.push(pro[i][j]); } while(q.size() > i) q.pop(); } int sum = 0; while(!q.empty()) { sum += q.top(); q.pop(); } printf("%d ", sum); } return 0; } /* 2 3 1 2 0 2 3 0 1 3 1 */
贪心 + 并查集
#include <bits/stdc++.h> using namespace std; struct node { int p, d; friend bool operator < (node A, node B) { return A.p > B.p; } }; const int maxn = 1e4 + 50; node cnt[maxn]; int pre[maxn]; int Find(int x) { return x == pre[x] ? x : pre[x] = Find(pre[x]); } void merge1(int x, int y) { pre[Find(x)] = Find(y); } int main() { int n; while(scanf("%d", &n) != EOF) { for(int i = 1; i <= 10000; i++) pre[i] = i; for(int i = 1; i <= n; i++) scanf("%d %d", &cnt[i].p, &cnt[i].d); sort(cnt + 1, cnt + n + 1); int ans = 0; for(int i = 1; i <= n; i++) { int fa = Find(cnt[i].d); if(fa > 0) ans += cnt[i].p, pre[fa] = fa - 1; } printf("%d ", ans); } return 0; }
边带权并查集
晚上睡觉的时候想,如果 2 --> 3,这样的链接在 4 后面,这样d[2] = 2, d[3] = 1, d[4] = 0,如果反复查询2的话,会变成不断累加? 答案是不会的,因为2 -- > 4。d数组要全部初始化成0
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <queue> #include <vector> using namespace std; const int maxn = 1e5; int pre[maxn * 2]; struct node { int l, r, st; }; node cur[maxn]; int x[maxn * 2]; int d[maxn * 2]; int Find(int x) { if(x == pre[x]) return x; int root = Find(pre[x]); d[x] ^= d[pre[x]]; return pre[x] = root; } int main() { int len, n; scanf("%d %d", &len, &n); int m = 0; memset(d, 0, sizeof(d)); for(int i = 1; i <= n; i++) { char s[10]; scanf("%d %d %s", &cur[i].l, &cur[i].r, s); cur[i].st = (s[0] == 'e' ? 0 : 1); // printf("%d ", cur[i].st); x[m++] = cur[i].l - 1; x[m++] = cur[i].r; } sort(x, x + m); m = unique(x, x + m) - x; for(int i = 0; i <= m; i++) pre[i] = i; for(int i = 1; i <= n; i++) { cur[i].l = lower_bound(x, x + m, cur[i].l - 1) - x; cur[i].r = lower_bound(x, x + m, cur[i].r) - x; int p = Find(cur[i].l); int q = Find(cur[i].r); if(p == q) { // printf("dasda "); if((d[cur[i].l] ^ d[cur[i].r]) == cur[i].st) continue; printf("%d ", i - 1); return 0; } else pre[p] = q, d[p] = d[cur[i].l] ^ d[cur[i].r] ^ cur[i].st; } printf("%d ", n); return 0; } /* 10 4 2 5 even 6 8 odd 3 7 odd 2 8 even */
边带权并查集:
要能看出它的传递性:
sum[l,r]表示l,r之间1的个数
如果sum[l,r]为奇数,那么sum[r]与sum[l-1]奇偶性不同;
如果sum[l,r]为偶数,那么sum[r]与sum[l-1]奇偶性相同。
借助传递性,比如sum[2,5] 是 even, sum[1]与sum[5]相同,sum[6,8]是odd,sum[5]与sum[8]不同,所以sum[1]与sum[8]不同。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e4 + 50; int pre[maxn * 2]; struct node { int l, r, st; }; node cur[maxn]; int x[maxn * 2]; int d[maxn * 2]; int Find(int x) { if(x == pre[x]) return x; int root = Find(pre[x]); d[x] ^= d[pre[x]]; return pre[x] = root; } int main() { int len, n; scanf("%d %d", &len, &n); int m = 0; for(int i = 1; i <= n; i++) { char s[10]; scanf("%d %d %s", &cur[i].l, &cur[i].r, s); cur[i].st = (s[0] == 'e' ? 0 : 1); // printf("%d ", cur[i].st); x[m++] = cur[i].l; x[m++] = cur[i].r; } sort(x, x + m); m = unique(x, x + m) - x; for(int i = 0; i <= m; i++) pre[i] = i; for(int i = 1; i <= n; i++) { cur[i].l = lower_bound(x, x + m, cur[i].l) - x; cur[i].r = lower_bound(x, x + m, cur[i].r) - x; int p = Find(cur[i].l - 1); int q = Find(cur[i].r); if(p == q) { // printf("dasda "); if((d[cur[i].l - 1] ^ d[cur[i].r]) == cur[i].st) continue; printf("%d ", i - 1); return 0; } else pre[p] = q, d[p] = d[cur[i].l - 1] ^ d[cur[i].r] ^ cur[i].st; } printf("%d ", n); return 0; } /* 10 4 2 5 even 6 8 odd 3 7 odd 2 8 even */
和上题一样。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 50; map<string, int> mp; int pre[maxn]; int d[maxn]; int Find(int x) { if(x == pre[x]) return x; int root = Find(pre[x]); d[x] ^= d[pre[x]]; return pre[x] = root; } int main() { int n, m, q; scanf("%d %d %d", &n, &m, &q); char s[25]; string tmp; for(int i = 1; i <= n; i++) scanf("%s", s), tmp = s, mp[s] = i, pre[i] = i, d[i] = 0; for(int i = 1; i <= m; i++) { int t; char s1[25], s2[25]; scanf("%d %s %s", &t, s1, s2); int x = mp[s1], y = mp[s2]; int ans = t == 1 ? 0 : 1; int p = Find(x); int q = Find(y); if(p == q) { if((d[x] ^ d[y]) == ans) printf("YES "); else printf("NO "); } else { pre[p] = q; d[p] = d[x] ^ d[y] ^ ans; printf("YES "); } } for(int i = 1; i <= q; i++) { char s1[25], s2[25]; scanf("%s %s", s1, s2); int x = mp[s1], y = mp[s2]; int p = Find(x); int q = Find(y); if(p != q) printf("3 "); else { printf("%d ", (d[x] ^ d[y]) == 1 ? 2 : 1); } } return 0; }
今天打完ningxia,听他们说最近有三道差不多的FFT,我看了三道题,然后看了两个题解,还是不太懂为啥那样做,我还是先把之前的FFT补补吧。