zoukankan      html  css  js  c++  java
  • 【USACO 2021 January Contest, Platinum】Problem 1. Sum of Distances

    ( ext{Solution})

    一个性质:两个 (K) 元组有边相连当且仅当每个点在对应的图中到 (1) 有奇偶性相同的路径
    那么我们就可以预处理每个图中的点到 (1) 的奇偶最短路
    再考虑路径长度,显然是 (min(max_{i=1}^k{odd_i}, max_{i=1}^k{even_i}))
    把它拆开 (max_{i=1}^k{odd_i} + max_{i=1}^k{even_i} - max_{i=1}^k(max(odd_i,even_i)))

    那么一个点的信息就成了三个
    分别算出这三个 (max) 即可
    先枚举 (max) 即最大的是多少,那么 (K) 元组其他位置就是其他图中小于 (max) 的点的个数乘起来
    可以从大枚举 (max),把点信息为 (max) 先算了,再删去这个点即可,那么就用线段树维护区间积即可,线段树下标表示第 (i) 个图剩余点的个数
    好处是线段树中剩余的点信息一定小于等于当前枚举的 (max),避免既要处理图不同又要处理信息大小关系的困境

    ( ext{Code})

    #include <cstdio> 
    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstring>
    #define re register
    #define LL long long
    using namespace std;
    
    const int K = 5e4 + 5, N = 2e5 + 5, INF = 0x3f3f3f3f;
    LL MOD = 1e9 + 7;
    int mx, k, n, m, h[N], tot, total, dis[N][2], col[N], vis[N][2];
    vector<int> g[N][3];
    struct node{int x, z;};
    queue<node> Q;
    
    struct edge{int to, nxt;}e[N << 1];
    inline void add(int x, int y)
    {
    	e[++tot] = edge{y, h[x]}, h[x] = tot;
    	e[++tot] = edge{x, h[y]}, h[y] = tot;
    }
    
    inline void read(int &x)
    {
    	x = 0; char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    }
    
    struct Segment{
    	#define ls (p << 1)
    	#define rs (ls | 1)
    	int tr[K << 2]; LL sum[K << 2];
    	void build(int p, int l, int r)
    	{
    		if (l == r) return void(sum[p] = 0);
    		int mid = (l + r) >> 1;
    		build(ls, l, mid), build(rs, mid + 1, r);
    	}
    	void update(int p, int l, int r, int x, int v)
    	{
    		if (x < l || x > r) return;
    		if (l == r) return void(sum[p] += v);
    		int mid = (l + r) >> 1;
    		if (x <= mid) update(ls, l, mid, x, v);
    		else update(rs, mid + 1, r, x, v);
    		sum[p] = sum[ls] * sum[rs] % MOD;
    	}
    	LL query(int p, int l, int r, int tl, int tr)
    	{
    		if (tl > r || tr < l) return 1;
    		if (tl <= l && r <= tr) return sum[p];
    		int mid = (l + r) >> 1;
    		LL res = 1;
    		if (tl <= mid) res = query(ls, l, mid, tl, tr);
    		if (tr > mid) res = res * query(rs, mid + 1, r, tl, tr) % MOD;
    		return res;
    	}
    }T;
    
    inline void spfa()
    {
    	for(re int j = 1; j <= n; j++) dis[j][0] = dis[j][1] = INF, vis[j][0] = vis[j][1] = 0;
    	dis[1][0] = 0, vis[1][0] = 1, Q.push(node{1, 0});
    	while (!Q.empty())
    	{
    		node now = Q.front(); Q.pop();
    		for(re int j = h[now.x]; j; j = e[j].nxt)
    		if (dis[e[j].to][now.z ^ 1] > dis[now.x][now.z] + 1)
    		{
    			dis[e[j].to][now.z ^ 1] = dis[now.x][now.z] + 1;
    			if (!vis[e[j].to][now.z ^ 1])
    				vis[e[j].to][now.z ^ 1] = 1, Q.push(node{e[j].to, now.z ^ 1});
    		}
    		vis[now.x][now.z] = 0;
    	}
    }
    
    inline LL solve(int z)
    {
    	T.build(1, 1, k);
    	for(re int i = mx; i >= 0; i--)
    		for(re int j = 0; j < g[i][z].size(); j++) T.update(1, 1, k, col[g[i][z][j]], 1);
    	LL res = 0;
    	for(re int i = mx; i; i--)
    		for(re int j = 0; j < g[i][z].size(); j++)
    		{
    			int now = g[i][z][j];
    			res = (res + T.query(1, 1, k, 1, col[now] - 1) * T.query(1, 1, k, col[now] + 1, k) % MOD * i % MOD) % MOD;
    			T.update(1, 1, k, col[now], -1);
    		}
    	return res;
    }
    
    int main()
    {
    	read(k);
    	for(re int i = 1; i <= k; i++)
    	{
    		tot = 0;
    		read(n), read(m);
    		for(re int j = 1, x, y; j <= m; j++) read(x), read(y), add(x, y);
    		spfa();
    		for(re int j = 1; j <= n; j++)
    		{
    			col[total + j] = i;
    			for(re int l = 0; l <= 1; l++)
    			if (dis[j][l] ^ INF) g[dis[j][l]][l].push_back(total + j);
    			if (max(dis[j][0], dis[j][1]) ^ INF) g[max(dis[j][0], dis[j][1])][2].push_back(total + j);
    			if (dis[j][0] ^ INF) mx = max(mx, dis[j][0]);
    			if (dis[j][1] ^ INF) mx = max(mx, dis[j][1]);
    		}
    		total += n;
    		for(re int i = 1; i <= n; i++) h[i] = 0;
    	}
    	printf("%lld
    ", (solve(0) + solve(1) - solve(2) + MOD) % MOD);
    }
    

    当然用 (STL)(vector)(queue) 虽然直观但终究是慢了

    ( ext{Code})

    #include <cstdio> 
    #include <iostream>
    #define re register
    #define LL long long
    using namespace std;
    
    const int K = 5e4 + 5, N = 2e5 + 5, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
    int mx, k, n, m, h[N], tot, total, dis[N][2], col[N], vis[N][2], g[N][3], Tot;
    struct node{int x, z;};
    node Q[N << 1];
    struct edge{int to, nxt;}e[N << 1], E[N << 1];
    inline void add(int x, int y)
    {
    	e[++tot] = edge{y, h[x]}, h[x] = tot;
    	e[++tot] = edge{x, h[y]}, h[y] = tot;
    }
    inline void Add(int x, int z, int y){E[++Tot] = edge{y, g[x][z]}, g[x][z] = Tot;}
    
    inline void read(int &x)
    {
    	x = 0; char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    }
    
    struct Segment{
    	#define ls (p << 1)
    	#define rs (ls | 1)
    	int tr[K << 2], sum[K << 2];
    	void build(int p, int l, int r)
    	{
    		if (l == r) return void(sum[p] = 0);
    		int mid = (l + r) >> 1;
    		build(ls, l, mid), build(rs, mid + 1, r);
    	}
    	void update(int p, int l, int r, int x, int v)
    	{
    		if (x < l || x > r) return;
    		if (l == r) return void(sum[p] += v);
    		int mid = (l + r) >> 1;
    		if (x <= mid) update(ls, l, mid, x, v);
    		else update(rs, mid + 1, r, x, v);
    		sum[p] = 1LL * sum[ls] * sum[rs] % MOD;
    	}
    	int query(int p, int l, int r, int tl, int tr)
    	{
    		if (tl > r || tr < l) return 1;
    		if (tl <= l && r <= tr) return sum[p];
    		int mid = (l + r) >> 1;
    		int res = 1;
    		if (tl <= mid) res = query(ls, l, mid, tl, tr);
    		if (tr > mid) res = 1LL * res * query(rs, mid + 1, r, tl, tr) % MOD;
    		return res;
    	}
    }T;
    
    inline void spfa()
    {
    	int head = 0, tail = 1;
    	for(re int j = 1; j <= n; j++) dis[j][0] = dis[j][1] = INF, vis[j][0] = vis[j][1] = 0;
    	dis[1][0] = 0, vis[1][0] = 1, Q[1] = node{1, 0};
    	while (head < tail)
    	{
    		node now = Q[++head];
    		for(re int j = h[now.x]; j; j = e[j].nxt)
    		if (dis[e[j].to][now.z ^ 1] > dis[now.x][now.z] + 1)
    		{
    			dis[e[j].to][now.z ^ 1] = dis[now.x][now.z] + 1;
    			if (!vis[e[j].to][now.z ^ 1])
    				vis[e[j].to][now.z ^ 1] = 1, Q[++tail] = node{e[j].to, now.z ^ 1};
    		}
    		vis[now.x][now.z] = 0;
    	}
    }
    
    inline int solve(int z)
    {
    	T.build(1, 1, k);
    	for(re int i = mx; i >= 0; i--)
    		for(re int j = g[i][z]; j; j = E[j].nxt) T.update(1, 1, k, col[E[j].to], 1);
    	int res = 0;
    	for(re int i = mx; i; i--)
    		for(re int j = g[i][z]; j; j = E[j].nxt)
    			res = (res + 1LL * T.query(1, 1, k, 1, col[E[j].to] - 1) * T.query(1, 1, k, col[E[j].to] + 1, k) % MOD * i % MOD) % MOD,
    			T.update(1, 1, k, col[E[j].to], -1);
    	return res;
    }
    
    int main()
    {
    	read(k);
    	for(re int i = 1; i <= k; i++)
    	{
    		tot = 0;
    		read(n), read(m);
    		for(re int j = 1, x, y; j <= m; j++) read(x), read(y), add(x, y);
    		spfa();
    		for(re int j = 1; j <= n; j++)
    		{
    			col[total + j] = i;
    			for(re int l = 0; l <= 1; l++)
    			if (dis[j][l] ^ INF) Add(dis[j][l], l, total + j);
    			if (max(dis[j][0], dis[j][1]) ^ INF) Add(max(dis[j][0], dis[j][1]), 2, total + j);
    			if (dis[j][0] ^ INF) mx = max(mx, dis[j][0]);
    			if (dis[j][1] ^ INF) mx = max(mx, dis[j][1]);
    		}
    		total += n;
    		for(re int i = 1; i <= n; i++) h[i] = 0;
    	}
    	printf("%d
    ", (1LL * solve(0) + solve(1) - solve(2) + MOD) % MOD);
    }
    
  • 相关阅读:
    spring boot +mybatis 操作sqlite数据库
    katalon studio教程之通过录制/回放创建测试用例
    #katalon studio# 安装和设置(Installation and Setup)
    NET Core 基于Aspect Injector 实现面向AOP编程
    NET Core 3.1使用AutoMapper实现对象映射
    给NET core 智能感知提示安装中文汉化包
    代码注释规范
    软件升级版本号迭代规范-Semantic Versioning
    使用阿里云的Helm私有仓库
    Helm操作指南
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15153919.html
Copyright © 2011-2022 走看看