[LDUoj 倍增] 题解

2023-11-20

细节的地方慢慢补充,欢迎提出问题,私聊/留言均可

A. 跳跳棋

在这里插入图片描述

较难

struct node
{
    int a, b, c;
    friend bool operator != (node a, node b)
    {
        if(a.a != b.a || a.b != b.b || a.c != b.c) return true;
        return false;
    }
    void srt()
    {
        int temp[] = {a, b, c};
        sort(temp, temp + 3);
        a = temp[0], b = temp[1], c = temp[2];
    }
} pnt1, pnt2;
node getRoot(node pnt, int &cnt)
{
    /// dis1 == dis2  -> return pnt ok;
    while(pnt.c - pnt.b != pnt.b - pnt.a)
    {
        int dis1 = pnt.b - pnt.a;
        int dis2 = pnt.c - pnt.b;
        if(dis1 < dis2)
        {
            int t = dis2 / dis1;
            if(dis2 % dis1 == 0) -- t;
            pnt.a += t * dis1;
            pnt.b += t * dis1;
            cnt += t;
        }
        else
        {
            int t = dis1 / dis2;
            if(dis1 % dis2 == 0) -- t;
            pnt.c -= t * dis2;
            pnt.b -= t * dis2;
            cnt +=  t;
        }
    }
    return pnt;
}
node moveUp(node pnt, int cnt)
{
    while(pnt.b - pnt.a != pnt.c - pnt.b && cnt)
    {
        int dis1 = pnt.b - pnt.a;
        int dis2 = pnt.c - pnt.b;
        if(dis1 < dis2)
        {
            int t = dis2 / dis1;
            if(dis2 % dis1 == 0) -- t;
            if(cnt < t) t = cnt;
            pnt.a += t * dis1;
            pnt.b += t * dis1;
            cnt -= t;
        }
        else
        {
            int t = dis1 / dis2;
            if(dis1 % dis2 == 0) -- t;
            if(cnt < t) t = cnt;
            pnt.c -= t * dis2;
            pnt.b -= t * dis2;
            cnt -= t;
        }
    }
    return pnt;
}
int main()
{
    cin >> pnt1.a >> pnt1.b >> pnt1.c;
    cin >> pnt2.a >> pnt2.b >> pnt2.c;
    pnt1.srt(), pnt2.srt();
    int cnt1 = 0, cnt2 = 0;
    node root1 = getRoot(pnt1, cnt1);
    node root2 = getRoot(pnt2, cnt2);
    if(root1 != root2)
    {
        puts("NO");
        return 0;
    }
    // puts("OK");
    if(cnt1 < cnt2) swap(pnt1, pnt2), swap(cnt1, cnt2);
    int l = 0, r = 1000000000;
    pnt1 = moveUp(pnt1, cnt1 - cnt2);
    int ans = 0;
    // puts("OK");
    while(l <= r)
    {
        int mid = l + r >> 1;
        // cout << l << "   " << r <<endl;
        if(!(moveUp(pnt1, mid) != moveUp(pnt2, mid)))
        {
            r = mid - 1;
            ans = mid;
        }
        else l = mid + 1;
        // puts("end of while");
    }
    puts("YES");
    cout << ans * 2 + cnt1 - cnt2 << endl;
    return 0;
}
/**


**/

B. 聚会

在这里插入图片描述

板子题

n个城市之间的距离是1
所以在求lca的过程中,深度的差值即可表示为距离
两个点a,b,之间的lca为_lca
那么这两个点之间的距离为dep[a] - dep[_lca] + dep[b] - dep[_lca],-> dep[a] + dep[b] - dep[_lca] * 2
这仅仅是两个点的情况
三个点的情况略有不同:
若三个点在同一棵子树上:

若三个点在同一条链上:

所以说我们要考虑任意两点之间的关系,然后求两次lca,第一次的lca即为可能的答案位置,最终答案要考虑所有情况中花费最小的那个

int n,m;
int root;
int head[maxn];
struct node {
	int u;
	int v;
	int w;
	int next;
} e[maxn];
int dep[maxn];/// save the depth of every node
int fa[maxn][30];
int lg[maxn];
int cnt = 0;
void init() {
	memset(head,-1,sizeof head);
}
void add(int u,int v) {
	e[cnt].u = u;
	e[cnt].v = v;
	e[cnt].next = head[u];
	head[u] = cnt ++;
}
void dfs(int cur,int rt) {
	fa[cur][0] = rt,dep[cur] = dep[rt] + 1;/// the depth of the current node changed
	for(int i=1; i <= lg[dep[cur]]; i++) {
		fa[cur][i] = fa[fa[cur][i-1]][i-1];
	}
	for(int i=head[cur]; ~i; i = e[i].next) { /// visit all linked nodes
		if(e[i].v != rt) dfs(e[i].v,cur);
	}
}
void cal() {
	for(int i=1; i<=n; i++) {
		lg[i] = lg[i-1] + (1 << lg[i-1] == i);/// 2 ^ lg[i-1] == i true + 1
	}
}
int lca(int x,int y) {
	if(dep[x] < dep[y]) swap(x,y);
	while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
	if(x == y) return y;
	/// big -> small
	for(int k = lg[dep[x]] - 1; k >= 0; k --) {
		if(fa[x][k] != fa[y][k]) {
			x = fa[x][k];
			y = fa[y][k];
		}
	}
	return fa[x][0];
}
int main() {
	cin >> n >> m;
	cal();
	init();
	for(int i=1; i<n; i++) {
		int u = read,v = read;
		add(u,v);
		add(v,u);
	}
	ll ans = inf,dis;
	int pos = 0;
	int lca1,lca2;
	dfs(1,0);
	for(int i=1; i<=m; i++) {
		ans = inf;
		int x = read,y = read,z = read;
		lca1  = lca(x,y);
		dis = dep[x] + dep[y] - 2 * dep[lca1];
		lca2 = lca(lca1,z);
		dis += dep[lca1] + dep[z] - 2 * dep[lca2];
		if(dis < ans) {
			ans = dis;
			pos = lca1;
		}
//		debug(lca1);
//		debug(dis);
		swap(x,z);
		lca1 = lca(x,y);
		dis = dep[x] + dep[y] - 2 * dep[lca1];
		lca2 = lca(lca1,z);
		dis += dep[lca1] + dep[z] - 2 * dep[lca2];
		if(dis < ans) {
			ans = dis;
			pos = lca1;
		}
		
		swap(y,z);
		lca1 = lca(x,y);
		dis = dep[x] + dep[y] - 2 * dep[lca1];
		lca2 = lca(lca1,z);
		dis += dep[lca1] + dep[z] - 2 * dep[lca2];
		if(dis <ans) {
			ans = dis;
			pos = lca1;
		}
		printf("%d %lld\n",pos,ans);
	}
	return 0;
}
/**
6 4
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6

6 2
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1

**/

C. 祖孙询问

在这里插入图片描述

板子题

求两点之间的lca,如果lca与其中一点相同,输出对应的值,反之输出0

int n,m;
int root;
int head[maxn];
struct node{
    int u;
    int v;
    int next;
}e[maxn];
int dep[maxn];/// save the depth of every node
int fa[maxn][30];
int lg[maxn];
int cnt = 0;
void init(){
    memset(head,-1,sizeof head);
}
void add(int u,int v){
    e[cnt].u = u;
    e[cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt ++;
}
void dfs(int cur,int rt){
    fa[cur][0] = rt,dep[cur] = dep[rt] + 1;/// the depth of the current node changed

    for(int i=1;i <= lg[dep[cur]];i++){
        fa[cur][i] = fa[fa[cur][i-1]][i-1];
    }
    for(int i=head[cur];~i;i = e[i].next){/// visit all linked nodes
        if(e[i].v != rt) dfs(e[i].v,cur);
    }
}
void cal(){
    for(int i=1;i<=n;i++){
        lg[i] = lg[i-1] + (1 << lg[i-1] == i);/// 2 ^ lg[i-1] == i true + 1
    }
}
int lca(int x,int y){
    if(dep[x] < dep[y]) swap(x,y);
    while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
    if(x == y) return y;
    /// big -> small
    for(int k = lg[dep[x]] - 1;k >= 0;k --){
        if(fa[x][k] != fa[y][k]){
            x = fa[x][k];
            y = fa[y][k];
        }
    }
    return fa[x][0];
}
int main() {
    cin >> n;
    cal();
    init();
    for(int i=1;i<=n;i++){
        int x = read,y = read;
        if(y == -1) {
        	root = x;
        	continue;
        }
        add(x,y);
        add(y,x);
    }
    dfs(root,0);
    cin >> m;
    for(int i=1;i<=m;i++){
        int x = read,y = read;
        int _lca = lca(x,y);
        if(_lca == x) puts("1");
        else if(_lca == y) puts("2");
        else puts("0");
    }
	return 0;
}/// ac_code


/**


**/

D. Dis

在这里插入图片描述

板子题

考虑在更新depth的时候,顺便更新一下两点之间的距离,(在题目中如果说任意两点之间的距离为1的情况,dis可以用depth代替)

typedef pair<int,int> PII;
int n,m;
int root;
int head[maxn];
struct node {
	int u;
	int v;
	int w;
	int next;
} e[maxn];
int dep[maxn];/// save the depth of every node
int fa[maxn][30];
ll dis[maxn];
int lg[maxn];
int cnt = 0;
map<PII,int> mp;
void init() {
	memset(head,-1,sizeof head);
}
void add(int u,int v,int w) {
	e[cnt].u = u;
	e[cnt].v = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt ++;
}
void dfs(int cur,int rt) {
	fa[cur][0] = rt,dep[cur] = dep[rt] + 1;/// the depth of the current node changed
	dis[cur] = dis[rt] + mp[ {rt,cur}];
	for(int i=1; i <= lg[dep[cur]]; i++) {
		fa[cur][i] = fa[fa[cur][i-1]][i-1];
	}
	for(int i=head[cur]; ~i; i = e[i].next) { /// visit all linked nodes
		if(e[i].v != rt) dfs(e[i].v,cur);
	}
}
void cal() {
	for(int i=1; i<=n; i++) {
		lg[i] = lg[i-1] + (1 << lg[i-1] == i);/// 2 ^ lg[i-1] == i true + 1
	}
}
int lca(int x,int y) {
	if(dep[x] < dep[y]) swap(x,y);
	while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
	if(x == y) return y;
	/// big -> small
	for(int k = lg[dep[x]] - 1; k >= 0; k --) {
		if(fa[x][k] != fa[y][k]) {
			x = fa[x][k];
			y = fa[y][k];
		}
	}
	return fa[x][0];
}
int main() {
	cin >> n >> m;
	cal();
	init();
	for(int i=1; i<n; i++) {
		int u = read,v = read,w = read;
		mp[{u,v}] = mp[{v,u}] = w;
		add(u,v,w);
		add(v,u,w);
	}
	dfs(1,0);
	for(int i=1; i<=m; i++) {
		int x = read,y = read;
		int _lca = lca(x,y);
		ll ans = dis[x] + dis[y] - 2 * dis[_lca];
		printf("%lld\n",ans);
	}
	return 0;
}
/**
2 2 
1 2 100 
1 2 
2 1

**/

E. 次小生成树(严格次小生成树)

在这里插入图片描述

切掉这个题需要掌握:dfs技巧 + lca + 倍增 + 维护次小边权 + 最小生成树
这个题写下来之后会有很大提高,而且会改掉写代码开内存的坏习惯
在这里插入图片描述

int n, m;
struct node {
	ll u, v, w;
	ll nex;
} e[maxn << 1];
int cnt;
int head[maxn << 1];
void init() {
	cnt = 0;

	for (int i = 1; i <= 2 * n; i++) {
		head[i] = -1;
	}
}
void add(ll u, ll v, ll w) {
	e[cnt].u = u;
	e[cnt].v = v;
	e[cnt].w = w;
	e[cnt].nex = head[u];
	head[u] = cnt ++;
}
ll bz[100007][20],ma[100007][20],mi[100007][20],depth[100007];
void dfs(ll u, ll fa) {
	bz[u][0] = fa;
	for (int i = head[u]; ~i; i = e[i].nex) {
		ll to = e[i].v;
		if (to == fa) continue;
		depth[to] = depth[u] + 1L;///depth inc
		ma[to][0] = e[i].w;
		mi[to][0] = -999999999999999;
		dfs(to, u);
	}
}
ll lca(ll x, ll y) {
	if (depth[x] < depth[y])
		swap(x, y);

	for (ll i = 18; i >= 0; i--) {
		if (depth[bz[x][i]] >= depth[y])
			x = bz[x][i];
	}

	if (x == y)
		return x;

	for (ll i = 18; i >= 0; --i) {
		if (bz[x][i] != bz[y][i]) {
			x = bz[x][i];
			y = bz[y][i];
		}
	}

	return bz[x][0];
}
int fa[maxn];
void fainit() {
	for (int i = 1; i <= 2 * n; i++)
		fa[i] = i;
}
ll find(ll x) {
	if (x == fa[x])
		return x;
	else
		return fa[x] = find(fa[x]);
}
node a[maxn];
bool cmp(node a, node b) {
	return a.w < b.w;
}
bool vis[maxn];
void cal() {
	for (ll i = 1; i <= 18; i++) {
		for (ll j = 1; j <= n; j++) {
			bz[j][i] = bz[bz[j][i - 1]][i - 1];
			ma[j][i] = max(ma[j][i - 1], ma[bz[j][i - 1]][i - 1]);
			mi[j][i] = max(mi[j][i - 1], mi[bz[j][i - 1]][i - 1]);

			if (ma[j][i - 1] > ma[bz[j][i - 1]][i - 1])
				mi[j][i] = max(mi[j][i], ma[bz[j][i - 1]][i - 1]);
			else if (ma[j][i - 1] < ma[bz[j][i - 1]][i - 1])
				mi[j][i] = max(mi[j][i], ma[j][i - 1]);
		}
	}
}
ll get(int u, int v, ll w) {
	ll ret = -inf;

	for (int i = 18; i >= 0; i--) {
		if (depth[bz[u][i]] >= depth[v]) {
			if (w != ma[u][i])
				ret = max(ret, ma[u][i]);
			else
				ret = max(ret, mi[u][i]);

			u = bz[u][i];
		}
	}

	return ret;
}
int main() {
	n = read,m = read;
	init();
	for(int i=1; i<=m; i++) {
		a[i].u = read,a[i].v = read,a[i].w = read;
	}
	fainit();
	sort(a+1,a+1+m,cmp);
	ll tot = 0;
	for(int i=1; i<=m; i++) {
		int fau = find(a[i].u);
		int fav = find(a[i].v);
		if(fau == fav) continue;
		tot += a[i].w;
		fa[fau] = fav;
		add(a[i].u,a[i].v,a[i].w);
		add(a[i].v,a[i].u,a[i].w);
		vis[i] = true;///used
	}
//	cout << tot <<endl;
	mi[1][0] = -inf;
	depth[1] = 0;
	dfs(1,-1);
	cal();
	ll ret = inf;
	for(int i=1; i<=m; i++) {
		if(!vis[i]) {
			int u = a[i].u;
			int v = a[i].v;
			ll w = a[i].w;
			int _lca = lca(u,v);
			ll maxx = get(u,_lca,w);
			ll mini = get(v,_lca,w);
			ret = min(ret,tot-max(maxx,mini)+w);
		}
	}
	cout << ret <<endl;
	return 0;
}
/**


**/

F. 异象石

在这里插入图片描述

难度适中

考虑增加一个点或减少一个点的时候,对答案产生了哪些贡献

#define PII pair<ll,ll>
map<PII, ll> mp;
ll n, m, _time = 0;
ll head[maxn];
struct node
{
    ll u, v, w;
    ll next;
} e[maxn << 1];
ll dep[maxn];/// save the depth of every node
ll fa[maxn][30], lg[maxn], cnt = 0;
ll ans;
ll dfn[maxn], id[maxn], vis[maxn], dis[maxn];
set<ll> s;
void init()
{
    cnt = 0;
    memset(head, -1, sizeof head);
}
void add(ll u, ll v, ll w)
{
    e[cnt].v = v;
    e[cnt].w = w;
    e[cnt].next = head[u];
    head[u] = cnt ++;
}
void dfs(ll cur, ll rt)
{
    dfn[cur] = ++_time;
    id[_time] = cur;
    fa[cur][0] = rt;
    dep[cur] = dep[rt] + 1; /// the depth of the current node changed
    dis[cur] = dis[rt] + mp[ {cur, rt}];
    for(int i = 1; i <= lg[dep[cur]]; i++)
    {
        fa[cur][i] = fa[fa[cur][i - 1]][i - 1];
    }
    for(int i = head[cur]; ~i; i = e[i].next) /// visit all linked nodes
    {
        if(e[i].v != rt) dfs(e[i].v, cur);
    }
}
void cal()
{
    for(int i = 1; i <= n; i++)
    {
        lg[i] = lg[i - 1] + (1LL << lg[i - 1] == i); /// 2 ^ lg[i-1] == i true + 1
    }
}

ll lca(ll x, ll y)
{
    if(dep[x] < dep[y]) swap(x, y);
    while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];

    if(x == y) return x;
    for(int k = lg[dep[x]] - 1; k >= 0; k --)
    {
        if(fa[x][k] != fa[y][k])
        {
            x = fa[x][k];
            y = fa[y][k];
        }
    }
    return fa[x][0];
}
ll getDis(ll u, ll v)
{
    ll _lca = lca(u, v);
    return dis[u] + dis[v] - 2LL * dis[_lca];
}
void update(ll x)
{
    ll y, z;
    set<ll>::iterator it;
    x = dfn[x];///time
    if(!vis[id[x]]) s.insert(x);

    it = s.lower_bound(x);
    if(it == s.begin()) y = *--s.end();
    else y = *--it;
    y = id[y];

    it = s.upper_bound(x);
    if(it == s.end()) z = *s.begin();
    else z = *it;
    z = id[z];

    if(vis[id[x]]) s.erase(x);
    x = id[x];
    int dis = getDis(x, y) + getDis(x, z) - getDis(y, z);
    if(!vis[x]) vis[x] = 1, ans += dis;
    else vis[x] = 0, ans -= dis;
}

signed main()
{
    cin >> n;
    cal();
    init();
    for(int i = 1; i < n; i++)
    {
        ll u = read, v = read, w = read;
        mp[ {u, v}] = w;
        mp[ {v, u}] = w;
        add(u, v, w);
        add(v, u, w);
    }
    dfs(1, 0);
    m = read;
    ll x;
    char c;
    for(int i = 1; i <= m; i++)
    {
        cin >> c;
        if(c == '?') printf("%lld\n", ans >> 1LL);
        else
        {
            scanf("%lld", &x);
            update(x);
        }
    }
    // cout << ans << endl;
    return 0;
}
/**
6
1 2 1
1 3 5
4 1 7
4 5 3
6 4 2
10
+ 3
+ 1
?
+ 6
?
+ 5
?
- 6
- 3
?

5
14
17
10

**/

G. 暗的连锁

在这里插入图片描述

难度适中

首先对n-1条边建图,然后对后来的m条边进行处理:
(从度的方面入手)

int u = read, v = read;
int _lca = lca(u, v);
deg[u] ++;
deg[v] ++;
deg[_lca] -= 2;
int n, m;
int root;
int head[maxn];
struct node
{
    int u;
    int v;
    int w;
    int next;
} e[maxn];
int dep[maxn];/// save the depth of every node
int fa[maxn][30];
int mini[maxn][30];
int lg[maxn];
int cnt = 0;
vector<int> son[maxn];
void init()
{
    memset(head, -1, sizeof head);
}
void add(int u, int v)
{
    e[cnt].u = u;
    e[cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt ++;
}
void dfs(int cur, int rt)
{
    fa[cur][0] = rt, dep[cur] = dep[rt] + 1; /// the depth of the current node changed
    for(int i = 1; i <= lg[dep[cur]]; i++)
    {
        fa[cur][i] = fa[fa[cur][i - 1]][i - 1];
    }
    for(int i = head[cur]; ~i; i = e[i].next) /// visit all linked nodes
    {
        if(e[i].v != rt) dfs(e[i].v, cur), son[cur].push_back(e[i].v);
    }
}
void cal()
{
    for(int i = 1; i <= n; i++)
    {
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i); /// 2 ^ lg[i-1] == i true + 1
    }
}
int lca(int x, int y)
{
    if(dep[x] < dep[y]) swap(x, y);
    while(dep[x] > dep[y])
    {
        x = fa[x][lg[dep[x] - dep[y]] - 1];
    }
    if(x == y) return x;
    for(int k = lg[dep[x]] - 1; k >= 0; k --)
    {
        if(fa[x][k] != fa[y][k])
        {
            x = fa[x][k];
            y = fa[y][k];
        }
    }
    return fa[x][0];
}
int deg[maxn];
int ans;
void get(int u)
{
    int siz = son[u].size();
    for(int i = 0; i < siz; i++)
    {
        int to = son[u][i];
        get(to);
        deg[u] += deg[to];
    }
    if(!fa[u][0]) return ;
    if(deg[u] == 1) ans ++;
    else if(deg[u] == 0) ans += m;
}
int main()
{
    cin >> n >> m;
    cal();
    init();
    for(int i = 1; i < n; i++)
    {
        int u = read, v = read;
        add(u, v);
        add(v, u);
    }
    dfs(1, 0);
    for(int i = 1; i <= m; i++)
    {
        int u = read, v = read;
        int _lca = lca(u, v);
        deg[u] ++;
        deg[v] ++;
        deg[_lca] -= 2;
    }
    get(1);
    cout << ans << endl;
    return 0;
}
/**
4 1 
1 2 
2 3 
1 4 
3 4

3

**/

H. 点的距离

在这里插入图片描述

板子题

考虑用深度代替距离即可

#define Clear(x,val) memset(x,val,sizeof x)
int n,m;
int root;
int head[maxn];
struct node {
	int u;
	int v;
	int w;
	int next;
} e[maxn << 1];
int dep[maxn];/// save the depth of every node
int fa[maxn][30];
ll dis[maxn];
int lg[maxn];
int cnt = 0;
void init() {
	memset(head,-1,sizeof head);
}
void add(int u,int v) {
	e[cnt].u = u;
	e[cnt].v = v;
	e[cnt].next = head[u];
	head[u] = cnt ++;
}
void dfs(int cur,int rt) {
	fa[cur][0] = rt,dep[cur] = dep[rt] + 1;/// the depth of the current node changed
	for(int i=1; i <= lg[dep[cur]]; i++) {
		fa[cur][i] = fa[fa[cur][i-1]][i-1];
	}
	for(int i=head[cur]; ~i; i = e[i].next) { /// visit all linked nodes
		if(e[i].v != rt) dfs(e[i].v,cur);
	}
}
void cal() {
	for(int i=1; i<=n; i++) {
		lg[i] = lg[i-1] + (1 << lg[i-1] == i);/// 2 ^ lg[i-1] == i true + 1
	}
}
int lca(int x,int y) {
	if(dep[x] < dep[y]) swap(x,y);
	while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
	if(x == y) return y;
	/// big -> small
	for(int k = lg[dep[x]] - 1; k >= 0; k --) {
		if(fa[x][k] != fa[y][k]) {
			x = fa[x][k];
			y = fa[y][k];
		}
	}
	return fa[x][0];
}
int main() {
	n = read;
	cal();
	init();
	for(int i=1; i<n; i++) {
		int u = read,v = read;
		add(u,v);
		add(v,u);
	}
	dfs(1,0);
	m = read;
	for(int i=1; i<=m; i++) {
		int x = read,y = read;
		int _lca = lca(x,y);
		ll ans = dep[x] + dep[y] - 2 * dep[_lca];
		printf("%lld\n",ans);
	}
	return 0;
}
/**
6
1 2
1 3
2 4
2 5
3 6
2
2 6
5 6

**/

l. 晨跑

在这里插入图片描述

大水题

求三个数的lcm

int main()
{
    ll a = read, b = read, c = read;
    ll ans = lcm(lcm(a,b),c);
    cout << ans <<endl;
    return 0;
}

J. 货物运输

在这里插入图片描述

较简单

在维护某节点的2次方级祖先的同时,记录下路径的最小承重,即为答案

int n, m;
int root;
int head[maxn];
struct node
{
    int u;
    int v;
    int w;
    int next;
} e[maxn];
int dep[maxn];/// save the depth of every node
int fa[maxn][30];
int mini[maxn][30];
int lg[maxn];
int cnt = 0;
void init()
{
    memset(head, -1, sizeof head);
}
void add(int u, int v, int w)
{
    e[cnt].u = u;
    e[cnt].v = v;
    e[cnt].w = w;
    e[cnt].next = head[u];
    head[u] = cnt ++;
}
void dfs(int cur, int rt, int val)
{
    fa[cur][0] = rt, dep[cur] = dep[rt] + 1; /// the depth of the current node changed
    mini[cur][0] = val;
    for(int i = 1; i <= lg[dep[cur]]; i++)
    {
        fa[cur][i] = fa[fa[cur][i - 1]][i - 1];
        mini[cur][i] = min(mini[cur][i - 1], mini[fa[cur][i - 1]][i - 1]);
    }
    for(int i = head[cur]; ~i; i = e[i].next) /// visit all linked nodes
    {
        if(e[i].v != rt) dfs(e[i].v, cur, e[i].w);
    }
}
void cal()
{
    for(int i = 1; i <= n; i++)
    {
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i); /// 2 ^ lg[i-1] == i true + 1
    }
}
int lca(int x, int y)
{
    int ans = 0x3f3f3f3f;
    if(dep[x] < dep[y]) swap(x, y);
    while(dep[x] > dep[y])
    {
        ans = min(ans, mini[x][lg[dep[x] - dep[y]] - 1]);
        x = fa[x][lg[dep[x] - dep[y]] - 1];
    }
    if(x == y) return ans;
    /// big -> small
    for(int k = lg[dep[x]] - 1; k >= 0; k --)
    {
        if(fa[x][k] != fa[y][k])
        {
            ans = min(ans, mini[x][k]);
            ans = min(ans, mini[y][k]);
            x = fa[x][k];
            y = fa[y][k];
        }
    }
    ans = min(ans, mini[x][0]);
    ans = min(ans, mini[y][0]);
    // return fa[x][0];
    return ans;
}
int main()
{
    cin >> n >> m;
    cal();
    init();
    for(int i = 1; i < n; i++)
    {
        int u = read, v = read, w = read;
        add(u, v, w);
        add(v, u, w);
    }
    dfs(1, 0, 0x3f3f3f3f);
    for(int i = 1; i <= m; i++)
    {
        int u = read, v = read;
        int ans = lca(u, v);
        printf("%d\n", ans);
    }
    return 0;
}
/**
6 5
1 2 2
2 3 5
2 4 2
2 5 3
5 6 1
2 4
6 2
1 3
3 5
1 6

**/

K. 数三角形

在这里插入图片描述

组合数学简单题

考虑容斥,减去不符合的情况
需要知道两个整数点之间的整数点的个数 博客第11条
在这里插入图片描述

ll cal(ll x){
	ll ret = x * (x - 1) * (x - 2);
	return ret / 6LL;
}
int n,m;
int main() {
    n = read,m = read;
    n ++,m ++;
    ll tot = cal(n * m) - n* cal(m) - m * cal(n);
    ll sub = 0;
    // cout << tot <<endl;
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		sub += (n - i) * (m - j) * (gcd(i,j) - 1);
    	}
    }
    cout << tot - sub * 2 <<endl;
	return 0;
}/// ac_code


/**


**/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[LDUoj 倍增] 题解 的相关文章

随机推荐

  • 组合测试方法PK正交分析方法

    测试过程中 我们经常遇到需要覆盖多个变化参数的测试场景 如我们测试BS配置控制客户端组织资源远程配置一个设备时 进行一个设备通道视频参数设置的各种组合测试 如下图 多数情况下 类似于这种多组合测试时 老员工则是依靠经验去进行有针对性的测试
  • C++ 实现获取系统名称

    项目中需要用到操作系统名及版本信息 下面是用两种方法实现的 一种是通过查询注册表 include stdafx h include
  • Qt QGraphicsItem及派生类设置是否可选中,是否可移动

    设置可选中 可移动 setFlags ItemIsSelectable ItemIsMovable 设置不可选中 setFlags flags ItemIsSelectable
  • 在计算机上搭建云服务

    首先是安装VirtualBox虚拟机 这里由于之前已经安装完成 所以不再一一演示 对于虚拟机储存位置的设置 VirtualBox菜单 管理 gt 全局设定 常规页面 选择 默认虚拟电脑位置 即可 创建虚拟机内部虚拟网络 VirtualBox
  • 堆栈01--用两个栈实现队列

    堆栈01 用两个栈实现队列 jz05 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 用两个栈来实现一个队列 完成队列的Push和Pop操作 队列中的元素为int类型 测试用例 队列先进先出 输入 1 2 输出 1 2 解析
  • U盘装系统教程,一键安装和U盘安装的区别

    装系统教程U盘安装篇 一键安装和U盘安装的区别 一键重装系统工具 优点 1 集成线上重装和本地备份还原功能 让用户多重选择 2 无人值守 无需电脑知识的小白用户也可以使用 3 用户可选择工具自带系统镜像安装 不需要单独下载 缺点 1 线上重
  • Elo评分算法原理与实现

    社交网络 里的Mark Zackburg被女朋友甩后 在舍友的启发下 充分发挥了技术宅男自娱自乐的恶搞天分 做出了Facemash网站 对学校女生的相貌进行排名打分 结果网站访问流量过大 直接把学校网络搞瘫痪了 Facemask大受欢迎的关
  • 创建vue项目,完整步骤

    1 安装nodejs node官网 https nodejs org en 检测是否安装成功 node v npm v 电脑上有多版本node时 需要用 nvm 管理工具 2 全局安装脚手架 vue cli npm install vue
  • Qt的信号和槽机制

    在C 中 对象与对象之间通信 要通过调用成员函数的方式来完成 而在Qt中提供了一种对象间的通信方式 信号与槽的机制 Qt通过QObject来提供这个通信机制 它的工作方式也很简单 通过QObject对象提供的connect连接函数将信号与处
  • SAP-ABAP-普通OOALV,OOALV分屏展示,发送邮件excel附件合并单元格,附件带框线,附件居中。

    功能展示 1 三个可拖动变换大小的屏幕 2 普通OOALV 3 带格式的邮件附件 三个表格 合并居中 单元格带框线 指定列宽 代码如下 复制可直接激活 没有include 创建程序后还有一些其他步骤 详情见后文 Report ZLQT OO
  • 工程和界面—Webstorm入门指南

    转载自http www 36ria com 5698 工程和界面 Webstorm入门指南 Webstorm中的工程 1 新建工程 Quick Start 界面新建工程 也可以点击顶部菜单栏 File gt New Project 弹出如下
  • MACD底背离选股公式——通达信、同花顺

    底背离 通达信版 同花顺版 DIFF EMA CLOSE 12 EMA CLOSE 26 DEA EMA DIFF 9 MACD 2 DIFF DEA QZQ BARSLAST REF MACD 1 lt 0 AND MACD gt 0 Q
  • c语言统计出现个数,C语言统计数字出现的个数

    程序功能 统计数字出现的个数 例如 输入1 2 3 1 2 4 2 3 1 输出 1 3 2 3 3 2 4 1 能看懂吗 就是1出现3次 2出现3次 3出现2次 4出现1次 define M 50 main int a M c 5 i n
  • SQLite、MySQL和PostgreSQL 三种关系数据库比较

    关系型数据库的使用已经有相当长的时间了 它们变得流行起来托了管理系统的福 关系模型被实现得相当的好 并且被证明是操作数据的好方法 特别是事务性强的应用 在这篇DigitalOcean文章中 我们将尝试理解一些最常用 最流行的关系型数据库管理
  • 正确打开visual studio2015

    找到visual studio2015的安装目录 点击其中的devenv exe打开
  • 02-RabbitMQ之Docker安装Rabbit单机与集群

    一 docker安装单机rabbit 1 查找rabbitmq镜像或者在docker仓库查看rabbitmq镜像 docker search rabbitmq 2 拉取最新的rabbitmq docker pull rabbitmq 3 运
  • KEIL经常出现 Encountered an improper argument 弹窗

    关于 keil5 使用在线调试时 经常出现 Encountered an improper argument 弹窗 经实测 可有如下方法 方法1 下载UV4 exe 替换本机电脑 Keil UV4目录下的UV4 exe 更换后 如果不能编译
  • 7-14 解一元一次方程 (17 分)

    请编写程序 解一元一次方程 ax b 0 一元一次方程求解公式为 x ab 求解要求 a 0 方程有唯一解 输出解 a 0 b 0 方程无解 输出no solution a 0 b 0 则方程有无穷多解 输出Infinitely solut
  • The absolute uri: http://java.sun.com/jsp/jstl/fmt cannot be resolved in either web.xml or the jar

    错误提示 org apache jasper JasperException file H netbeans workspace netbeans 6 9 ShoppingSystemOnline build web system fron
  • [LDUoj 倍增] 题解

    星星之火 可以燎原 细节的地方慢慢补充 欢迎提出问题 私聊 留言均可 A 跳跳棋 较难 B 聚会 板子题 C 祖孙询问 板子题 D Dis 板子题 E 次小生成树 严格次小生成树 难 F 异象石 难度适中 G 暗的连锁 难度适中 H 点的距