• 2021.4.8


    (mathcal{A})

    重建计划

    #include <bits/stdc++.h>
    using namespace std;
    //namespace cyl {
    const int N = (int)1e5 + 5;
    const double eps = 1e-4;
    double mid;
    int siz[N], mxs[N], cnt, ans = 0, n, L, U, S, rt, num[N], q[N], o;
    bool vis[N], flag;
    vector<vector<pair<int, double> > > son[N];
    vector<pair<int, double> > *c, p, np;
    vector<pair<int, int> > G[N];
    vector<int> E[N];
    void getrt(int u, int fa) {
    	siz[u] = 1, mxs[u] = 0;
    	for (auto x : G[u])
    		if (!vis[x.first] && x.first != fa) {
    			getrt(x.first, u);
    			siz[u] += siz[x.first];
    			mxs[u] = max(mxs[u], siz[x.first]);
    		}
    	mxs[u] = max(mxs[u], S - siz[u]);
    	if (rt == -1 || mxs[rt] > mxs[u]) rt = u;
    }
    void dfs(int u, int fa, int t, double d) {
    	c->push_back(make_pair(t, d));
    	for (auto x : G[u])
    		if (!vis[x.first] && x.first != fa)
    			dfs(x.first, u, t + 1, d + x.second);
    }
    void div(int u) {
    	vis[u] = 1;
    	son[u].push_back(*(new vector<pair<int, double> >));
    	for (auto x : G[u])
    		if (!vis[x.first]) {
    			son[u].push_back(*(new vector<pair<int, double> >));
    			c = &son[u][++num[u]];
    			dfs(x.first, 0, 1, x.second);
    			sort(c->begin(), c->end());
    		}
    	sort(son[u].begin(), son[u].end(), [](vector<pair<int, double> > &a, vector<pair<int, double> > &b) { return a.size() < b.size(); });
    	for (auto x : G[u])
    		if (!vis[x.first]) {
    			S = siz[x.first], rt = -1, getrt(x.first, 0);
    			E[u].push_back(rt);
    			div(rt);
    		}
    }
    void work(int u) {
    	if (flag) return;
    	p.clear();
    	p.push_back(make_pair(0, 0));
    	for (int i = 1; i <= num[u]; ++i) {
    		int l = 1, r = 0, j = 0;
    		for (int i2 = son[u][i].size() - 1; i2 >= 0; --i2) {
    			auto x = son[u][i][i2];
    			while (j < p.size() && p[j].first + x.first <= U) {
    				while (l <= r && p[j].second - mid * p[j].first >= p[q[r]].second - mid * p[q[r]].first) --r;
    				q[++r] = j++;
    			}
    			while (l <= r && p[q[l]].first + x.first < L) ++l;
    			if (l <= r && p[q[l]].second - mid * p[q[l]].first + x.second - mid * x.first > -eps) {
    				flag = 1;
    				break;
    			}
    		}
    		np.clear();
    		for (int j = 0, k = 0; j < p.size() || k < son[u][i].size(); )
    			if (k == son[u][i].size() || j < p.size() && p[j] < son[u][i][k])
    				np.push_back(p[j++]);
    			else
    				np.push_back(son[u][i][k++]);
    		swap(p, np);
    	}
    	for (auto v : E[u]) work(v);
    }
    bool check() {
    	flag = 0;
    	work(o);
    	return flag;
    }
    int main() {
    	scanf("%d%d%d", &n, &L, &U);
    	for (int i = 1, u, v, w; i < n; ++i) {
    		scanf("%d%d%d", &u, &v, &w);
    		G[u].push_back(make_pair(v, w));
    		G[v].push_back(make_pair(u, w));
    	}
    	S = n, rt = -1, getrt(1, 0);
    	o = rt;
    	div(rt);
    	double l = 0, r = 1e6;
    	while (r - l >= eps) {
    		mid = (l + r) / 2;
    		if (check()) l = mid;
    		else r = mid;
    	}
    	printf("%.3lf
    ", l);
    	return 0;
    }
    //} int main() { return cyl::main(); } 
    

    (mathcal{B})

    树分块,大概有这样的一些方法:

    1. 王室联邦分块法:可以保证每个块的大小和直径都不超过2√N−1,但是不保证块联通
    2. DFS序分块法:首先是好写(毕竟转化成了序列问题),严格保证块大小√N,但是不保证直径,也不保证联通。处理子树信息比较方便
    3. size分块:检查当前节点的父亲所在块的大小,如果小于√N就把当前节点加入进去,不然新开块。块大小最坏√N,保证块内联通,还保证直径,多么优美啊可惜不能保证块个数(一个菊花图就死了)(摘自https://www.cnblogs.com/hua-dong/p/8275227.html)
    4. 按dep模块大小分类(代码2)

    糖果公园

    #include <bits/stdc++.h>
    using namespace std;
    //namespace cyl {
    const int N = (int)1e5 + 5;
    int sub[N], fa[N], son[N], stk[N], top[N], siz, tp, bid[N], dep[N], cnt[N], w[N], val[N], c[N], qx[N], qy[N], qk[N], qu[N], qv[N], qz[N];
    bool vis[N];
    int n, m, q, cc[N], ccnt, qcnt, id[N], oooo;
    long long ret, ans[N];
    vector<int> G[N];
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while (c > -1 && c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    	if (c == -1) return 0;
    	while (c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
    	return x * f;
    }
    void dfs1(int u) {
    	int bt = tp;
    	stk[++tp] = u;
    //	if (tp >= siz) {
    //		++oooo;
    //		for (int i = 1; i <= tp; ++i) bid[stk[i]] = oooo;
    //		tp = 0;
    //	}
    	sub[u] = 1;
    	int t = -1;
    	for (int v : G[u])
    		if (v != fa[u]) {
    			dep[v] = dep[u] + 1;
    			fa[v] = u;
    			dfs1(v);
    			if (tp - bt > siz) {
    				++oooo;
    				while (tp != bt) bid[stk[tp--]] = oooo;
    			}
    			sub[u] += sub[v];
    			if (sub[v] > t) {
    				t = sub[v];
    				son[u] = v;
    			}
    		}
    }
    void dfs2(int u, int t) {
    	top[u] = t;
    	if (son[u] == 0) return;
    	dfs2(son[u], t);
    	for (int v : G[u])
    		if (v != fa[u] && v != son[u])
    			dfs2(v, v);
    }
    int lca(int u, int v) {
    	while (top[u] != top[v]) {
    		if (dep[top[u]] < dep[top[v]]) swap(u, v);
    		u = fa[top[u]];
    	}
    	return dep[u] < dep[v] ? u : v;
    }
    void ins(int u) {
    	++cnt[c[u]];
    	ret += 1ll * w[cnt[c[u]]] * val[c[u]];
    }
    void del(int u) {
    	ret -= 1ll * w[cnt[c[u]]] * val[c[u]];
    	--cnt[c[u]];
    }
    void ver1(int k) {
    	if (vis[qx[k]]) del(qx[k]);
    	c[qx[k]] = qy[k];
    	if (vis[qx[k]]) ins(qx[k]);
    }
    void ver2(int k) {
    	if (vis[qx[k]]) del(qx[k]);
    	c[qx[k]] = qz[k];
    	if (vis[qx[k]]) ins(qx[k]);
    }
    void update(int u) {
    	if (vis[u]) vis[u] = 0, del(u);
    	else vis[u] = 1, ins(u);
    }
    void work(int u, int v) {
    	while (u != v) {
    		if (dep[u] < dep[v]) swap(u, v);
    		update(u);
    		u = fa[u];
    	}
    }
    int main() {
    	n = read(), m = read(), q = read(), siz = pow(n, 0.6666);
    	for (int i = 1; i <= m; ++i) val[i] = read();
    	for (int i = 1; i <= n; ++i) w[i] = read();
    	for (int i = 1; i < n; ++i) {
    		int u = read(), v = read();
    		G[u].push_back(v);
    		G[v].push_back(u);
    	}
    	for (int i = 1; i <= n; ++i) cc[i] = c[i] = read();
    	dfs1(1);
    	dfs2(1, 1);
    	++oooo;
    	for (int i = 1; i <= tp; ++i) bid[stk[i]] = oooo;
    	for (int i = 1; i <= q; ++i) {
    		int op = read();
    		if (op == 0) {
    			qx[++ccnt] = read(), qy[ccnt] = read();
    			qz[ccnt] = cc[qx[ccnt]];
    			cc[qx[ccnt]] = qy[ccnt];
    		} else {
    			qu[++qcnt] = read(), qv[qcnt] = read();
    			qk[qcnt] = ccnt;
    			id[qcnt] = qcnt;
    		}
    	}
    	sort(id + 1, id + qcnt + 1, [](int x, int y) {
    		return bid[qu[x]] < bid[qu[y]] || bid[qu[x]] == bid[qu[y]] && bid[qv[x]] < bid[qv[y]] ||
    		bid[qu[x]] == bid[qu[y]] && bid[qv[x]] == bid[qv[y]] && qk[x] < qk[y]; });
    	int u = 1, v = 1, ver = 0;
    	update(1);
    	for (int i = 1; i <= qcnt; ++i) {
    		int x = id[i];
    		if (u != qu[x]) work(u, qu[x]);
    		if (v != qv[x]) work(v, qv[x]);
    		update(lca(u, v));
    		update(lca(qu[x], qv[x]));
    		u = qu[x];
    		v = qv[x];
    		while (ver < qk[x]) ver1(++ver);
    		while (ver > qk[x]) ver2(ver--);
    		ans[x] = ret;
    	}
    	for (int i = 1; i <= qcnt; ++i) printf("%lld
    ", ans[i]);
    	return 0;
    }
    //} int main() { return cyl::main(); }
    

    Children Trips

    题意:给定一棵树n个点,边权为1或2。有m个询问,每次给出u,v,p。表示要从点u到点v,每天只能至多p的长度,且只能在节点处停留。对于每个询问,求至少需要几天。

    主要方法:对于这种指定方向跳的题目,在序列上有分块的做法,在树上也可以用。可以发现每次的只询问一条路径。所以选择限制直径、限制个数、不限制大小的树分块。

    1、对于(p>sqrt{n})的情况,可以证明暴力跳的话不会超过(O(sqrt{n}))次。
    2、对于(p<sqrt{n})的情况,可以预处理每个点每种p的答案。然后每次一块一块跳,由于限制了个数,所以也是(O(sqrt{n}))的。

    考虑一个询问u,v,p。令lca(u,v)=l。可以证明从u到l每天跳最多+从v到l每天跳最多=直接从u到v每天条最多=答案。需要注意的是,u到l最后一天剩下距离x,v到l最后一天剩下距离y,如果(x+y>=p)那么答案可以减少1。

    #include <bits/stdc++.h>
    using namespace std;
    int n, w, fa[100005], d[100005], m, key[100005], p, fly[100005][680], stp[100005][680], lef[100005][680];
    vector<pair<int, int> > G[100005];
    int dfs1(int u, int dep) {
    	int siz = 1;
    	for (int i = 0; i < G[u].size(); ++i) {
    		int v = G[u][i].first;
    		if (v == fa[u])
    			continue;
    		d[v] = d[u] + G[u][i].second;
    		fa[v] = u;
    		siz += dfs1(v, dep + 1);
    	}
    	if (dep % w == 1 && (u == 1 || siz >= w)) {
    		key[u] = u;
    		siz = 0;
    	}
    	return siz;
    }
    void dfs2(int u) {
    	if (!key[u])
    		key[u] = key[fa[u]];	
    	fly[u][0] = u;
    	for (int i = 1; i <= w + w; ++i) {
    		fly[u][i] = fly[u][i - 1];
    		if (fly[u][i] != key[u] && d[u] - d[fa[fly[u][i]]] <= i)
    			fly[u][i] = fa[fly[u][i]];
    		if (fly[u][i] == key[u]) {
    			stp[u][i] = 1;
    			lef[u][i] = i - (d[u] - d[key[u]]);
    		} else {
    			stp[u][i] = stp[fly[u][i]][i] + 1;
    			lef[u][i] = lef[fly[u][i]][i];
    		}
    	}
    	for (int i = 0; i < G[u].size(); ++i) {
    		int v = G[u][i].first;
    		if (v == fa[u])
    			continue;
    		dfs2(v);
    	}
    }
    int LCA(int u, int v) {
    	while (key[u] != key[v]) {
    		if (d[key[u]] < d[key[v]])
    			swap(u, v);
    		u = fa[key[u]];
    	}
    	while (u != v) {
    		if (d[u] < d[v])
    			swap(u, v);
    		u = fa[u];
    	}
    	return u;
    }
    int work(int u, int e, int &s) {
    	if (u == e)
    		return 0;
    	int LEF = 0;
    	if (p > 2 * w) {
    		while (key[u] != key[e]) {
    			if (d[u] - d[fa[key[u]]] <= LEF)
    				LEF -= d[u] - d[fa[key[u]]];
    			else {
    				++s;
    				LEF = p - d[fly[u][LEF]] + d[fa[key[u]]];
    			}
    			u = fa[key[u]];
    		}
    	} else {
    		while (key[u] != key[e]) {
    			if (d[u] - d[fa[key[u]]] <= LEF)
    				LEF -= d[u] - d[fa[key[u]]];
    			else {
    				u = fly[u][LEF];
    				s += stp[u][p];
    				LEF = lef[u][p];
    				if (d[key[u]] - d[fa[key[u]]] <= LEF)
    					LEF -= d[key[u]] - d[fa[key[u]]];
    				else {
    					++s;
    					LEF = p - d[key[u]] + d[fa[key[u]]];
    				}
    			}
    			u = fa[key[u]];
    		}
    	}
    	while (u != e) {
    		if (d[u] - d[fa[u]] <= LEF)
    			LEF -= d[u] - d[fa[u]];
    		else {
    			++s;
    			LEF = p - d[u] + d[fa[u]];
    		}
    		u = fa[u];
    	}
    	return LEF;
    }
    int main() {
    	scanf("%d", &n);
    	w = sqrt(n);
    	for (int i = 1; i < n; ++i) {
    		int u, v, w;
    		scanf("%d%d%d", &u, &v, &w);
    		G[u].push_back(make_pair(v, w));
    		G[v].push_back(make_pair(u, w));
    	}
    	dfs1(1, 1);
    	dfs2(1);
    	scanf("%d", &m);
    	while (m--) {
    		int u, v;
    		scanf("%d%d%d", &u, &v, &p);
    		int lca = LCA(u, v), s1 = 0, s2 = 0;
    		int l1 = work(u, lca, s1);
    		int l2 = work(v, lca, s2);
    		printf("%d
    ", s1 + s2 - (l1 + l2 >= p));
    	}
    	return 0;
    }
    ```
  • 相关阅读:
    20191005
    20191004-gugugu公告
    20191003
    10.2 一天
    考试总结 模拟$105$
    考试总结 模拟$104$
    考试总结 模拟$103$
    考试总结 模拟$102$
    考试总结 模拟$101$
    考试总结 模拟$100$
  • 原文地址:https://www.cnblogs.com/herald/p/14631466.html
Copyright © 2020-2023  润新知