Problem 1001
Problem 1002
考虑把每个询问拆分成2个单独的询问。
拆分后的询问为(s, t, x)。
也就是询问从s到t的最短路上所有权值小于等于x的点的权值总和。
我们把(s, t, a, b)拆成(s, t, a - 1) 和(s, t, b)。
那么第二个询问减去第一个询问的答案就是原来这个询问的答案。
我们把这2m个询问离线,以x为关键字升序排序。
这棵树的初始状态:所有点的权值都为0。
然后依次处理每个询问,先看有哪些点的权值小于等于当前询问的x值。
我们要保证当前所有满足条件的点都已经被更新到树上,如果还没更新就需要更新。
已经更新的不需要更新。
同时那些不满条件的点不在树上。
这个过程用双指针维护即可(但比赛的时候我为了省时间直接写了二分)
这样更新的总次数为n。
更新和查询用树链剖分维护就可以了。
时间复杂度$O(nlog^{2}(n) + mlogm + mlogn)$ (我的程序的复杂度)
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R typedef long long LL; const int N = 1e5 + 10; struct query_node{ int x, y; LL a, b; } q[N]; struct query_Node{ int x, y; LL val; int id; LL ans; friend bool operator < (const query_Node &a, const query_Node &b){ return a.val < b.val; } } qu[N << 1]; struct Val{ int id; LL val; friend bool operator < (const Val &a, const Val &b){ return a.val < b.val; } } num[N]; vector <int> v[N]; int son[N], father[N], sz[N], deep[N], top[N], f[N], fp[N]; int n, m, cnt, tot, upnow; LL a[N], ret[N], Num[N], sum[N << 2]; bool cmp(const query_Node &a, const query_Node &b){ if (a.id != b.id) return a.id < b.id; else return a.val < b.val; } void dfs1(int x, int fa, int dep){ deep[x] = dep; father[x] = fa; son[x] = 0; sz[x] = 1; for (auto u : v[x]){ if (u == fa) continue; dfs1(u, x, dep + 1); sz[x] += sz[u]; if (sz[son[x]] < sz[u]) son[x] = u; } } void dfs2(int x, int tp){ top[x] = tp; f[x] = ++tot; fp[f[x]] = x; if (son[x]) dfs2(son[x], tp); for (auto u : v[x]){ if (u == father[x] || u == son[x]) continue; dfs2(u, u); } } inline void pushup(int i){ sum[i] = sum[i << 1] + sum[i << 1 | 1]; } void update(int i, int L, int R, int pos, LL val){ if (L == R && L == pos){ sum[i] = val; return ; } int mid = (L + R) >> 1; if (pos <= mid) update(lson, pos, val); if (pos > mid) update(rson, pos, val); pushup(i); } LL query_sum(int i, int L, int R, int l, int r){ if (L == l && R == r) return sum[i]; int mid = (L + R) >> 1; if (r <= mid) return query_sum(lson, l, r); else if (l > mid) return query_sum(rson, l, r); else return query_sum(lson, l, mid) + query_sum(rson, mid + 1, r); } LL find_sum(int x, int y){ int f1 = top[x], f2 = top[y]; LL ret = 0; for (; f1 != f2; ){ if (deep[f1] < deep[f2]) swap(f1, f2), swap(x, y); ret += query_sum(1, 1, n, f[f1], f[x]); x = father[f1], f1 = top[x]; } if (x == y) return ret + query_sum(1, 1, n, f[x], f[y]); if (deep[x] > deep[y]) swap(x, y); return ret + query_sum(1, 1, n, f[x], f[y]); } int main(){ while (~scanf("%d%d", &n, &m)){ rep(i, 1, n) scanf("%lld", a + i); rep(i, 0, n + 1) v[i].clear(); rep(i, 2, n){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } cnt = 0; rep(i, 1, m){ scanf("%d%d%lld%lld", &q[i].x, &q[i].y, &q[i].a, &q[i].b); ++cnt; qu[cnt].x = q[i].x; qu[cnt].y = q[i].y; qu[cnt].val = q[i].a - 1LL; qu[cnt].id = i; ++cnt; qu[cnt].x = q[i].x; qu[cnt].y = q[i].y; qu[cnt].val = q[i].b; qu[cnt].id = i; } sort(qu + 1, qu + cnt + 1); tot = 0; dfs1(1, 0, 0); dfs2(1, 1); rep(i, 1, n) num[i].val = a[i], num[i].id = i; sort(num + 1, num + n + 1); rep(i, 1, n) Num[i] = num[i].val; memset(sum, 0, sizeof sum); upnow = 0; rep(i, 1, cnt){ int pos = upper_bound(Num + 1, Num + n + 1, qu[i].val) - Num - 1; rep(j, upnow + 1, pos){ update(1, 1, n, f[num[j].id], num[j].val); } qu[i].ans = find_sum(qu[i].x, qu[i].y); upnow = pos; } sort(qu + 1, qu + cnt + 1, cmp); rep(i, 1, m) ret[i] = qu[i * 2].ans - qu[i * 2 - 1].ans; rep(i, 1, m - 1) printf("%lld ", ret[i]); printf("%lld ", ret[m]); } return 0; }
Problem 1003
Problem 1004
Problem 1005
这道题我知道的有两种做法。
一个是缩点为DAG,则如果在拓扑序中出现了有两个及以上入度为0的点则不合法。
另一种是用bitset优化Floyd。
因为边数只有6000,所以不会TLE。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 1e3 + 10; int n, m; bitset <N> f[N]; bool fl; int T; int main(){ scanf("%d", &T); while (T--){ scanf("%d%d", &n, &m); rep(i, 0, n + 1) f[i].reset(); rep(i, 1, m){ int x, y; scanf("%d%d", &x, &y); f[x][y] = 1; } rep(i, 1, n) rep(j, 1, n) if (f[j][i]) f[j] |= f[i]; fl = true; rep(i, 1, n - 1){ rep(j, i + 1, n){ if (!(f[i][j] || f[j][i])){ fl = false; break; } } if (!fl) break; } puts(fl ? "I love you my love and our love save us!" : "Light my fire!"); } return 0; }
Problem 1006
Problem 1007
Problem 1010
比赛时居然这题会卡这么长时间
一开始以为之前有类似的题 直接模拟就行
后来发现这题数据范围比之前那题大
因此需要用dp进行转移
另外 这题细节较多 需要注意
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 using namespace std; 13 bool matchTmp(char *str, char *pattern){ 14 if(*str=='