ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ICPC2021 上海 Life is a Game 和 NOI2018 归程

2022-08-11 13:30:47  阅读:172  来源: 互联网

标签:200000 ICPC2021 int 400000 Life leq Game 保证 1500


Life is a Game

Life is a game.

The world can be regarded as an undirected connected graph of \(n\) cities and \(m\) undirected roads between the cities. Now you, the life game player, are going to play the life game on the world graph.

Initially, you are at the \(x\)-th city and of \(k\) social ability points. You can earn social ability points by living and working. Specifically, you can earn \(a_i\) social ability points by living and working in the \(i\)-th city. But in this problem, you cannot earn social ability points duplicatedly in one city, so you want to travel the world and earn more social ability points. However, the roads are not easy. Specifically, there is an ability threshold \(w_i\) for the \(i\)-th road, you should be of at least \(w_i\) social ability points to go through the road. Moreover, Your social ability point will not decrease when passing roads but just need to be at least \(w_i\) if you want to go through the i-th road.

So as you can see, the life game is just living, working and traveling repeatedly. There are \(q\) game saves. For each game save, the initial city and social ability point is given and the player has not lived or worked in any city. Now you, the real life game player, need to determine the maximum possible number of social ability points you can have in the end of the game and output it for each given game save.

\(1\le n,m,q \le 10^5\)

题解

显然我们需要用到Kruskal重构树。

与板子唯一不同的地方在于,我们要把边上对社交能力总和的限制改为对社交能力初始值的限制。

时间复杂度\(O(n\log n)\)。

constexpr int N=2e5+10;
int a[N];

struct Edge{
    int x, y, w;
}edge[N];

namespace US{ // Union Set
    int fa[N];

    void init(int n){
        for(int i=1; i<=n; ++i) fa[i]=i;
    }
    int find(int x){
        return fa[x]==x? x: fa[x]=find(fa[x]);
    }
    void merge(int x, int y){
        fa[find(x)]=find(y);
    }
}

int sum[N], fa[N][18], lim[N][18];

int main(){
    int n=read<int>(), m=read<int>(), q=read<int>();
    for(int i=1; i<=n; ++i)
        sum[i]=read(a[i]);
    for(int i=1; i<=m; ++i)
        read(edge[i].x), read(edge[i].y), read(edge[i].w);
    sort(edge+1, edge+m+1, [](const Edge& a, const Edge& b)->bool{
        return a.w<b.w;
    });
    US::init(n+m);
    for(int i=1; i<=m; ++i){
        int x=edge[i].x, y=edge[i].y, w=edge[i].w;
        if(US::find(x)==US::find(y)) continue;
        sum[n+i]=sum[US::find(x)]+sum[US::find(y)];
        fa[US::find(x)][0]=fa[US::find(y)][0]=n+i;
        lim[US::find(x)][0]=w-sum[US::find(x)];
        lim[US::find(y)][0]=w-sum[US::find(y)];
        // cerr<<US::find(x)<<" -> "<<n+i<<" lim="<<lim[US::find(x)][0]<<endl;
        // cerr<<US::find(y)<<" -> "<<n+i<<" lim="<<lim[US::find(y)][0]<<endl;
        US::merge(x, n+i), US::merge(y, n+i);
    }
    for(int i=n+m; i>=1; --i)if(sum[i]) // edge in use
        for(int j=1; j<=17; ++j){
            fa[i][j]=fa[fa[i][j-1]][j-1];
            lim[i][j]=max(lim[i][j-1], lim[fa[i][j-1]][j-1]);
        }
    while(q--){
        int x=read<int>(), k=read<int>();
        for(int i=17; i>=0; --i)if(fa[x][i])
            if(k>=lim[x][i]) x=fa[x][i];
        printf("%d\n", k+sum[x]);
    }
    return 0;
}

归程

题目背景

本题因为一些原因只能评测16组数据。

剩下的四组数据:https://www.luogu.org/problemnew/show/U31655

题目描述

本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。 魔力之都可以抽象成一个 nnn 个节点、mmm 条边的无向连通图(节点的编号从 111 至 nnn)。我们依次用 l,al,al,a 描述一条边的长度、海拔。 作为季风气候的代表城市,魔力之都时常有雨水相伴,因此道路积水总是不可避免 的。由于整个城市的排水系统连通,因此有积水的边一定是海拔相对最低的一些边。我们用水位线来描述降雨的程度,它的意义是:所有海拔不超过水位线的边都是有积水的。

Yazid 是一名来自魔力之都的OIer,刚参加完ION2018 的他将踏上归程,回到他 温暖的家。 Yazid 的家恰好在魔力之都的 111 号节点。对于接下来 QQQ 天,每一天Yazid 都会告诉你他的出发点 vvv ,以及当天的水位线ppp。 每一天,Yazid 在出发点都拥有一辆车。这辆车由于一些故障不能经过有积水的边。 Yazid 可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。 需要特殊说明的是,第二天车会被重置,这意味着:

  • 车会在新的出发点被准备好。
  • Yazid 不能利用之前在某处停放的车。

Yazid 非常讨厌在雨天步行,因此他希望在完成回家这一目标的同时,最小化他步行经过的边的总长度。请你帮助 Yazid 进行计算。 本题的部分测试点将强制在线,具体细节请见【输入格式】和【子任务】。

输入输出格式

输入格式:

单个测试点中包含多组数据。输入的第一行为一个非负整数TTT,表示数据的组数。

接下来依次描述每组数据,对于每组数据:

第一行 222 个非负整数 n,mn,mn,m,分别表示节点数、边数。

接下来 mmm 行,每行 444 个正整数u,v,l,au, v, l, au,v,l,a,描述一条连接节点 u,vu, vu,v 的、长度为 lll、海拔为 aaa 的边。 在这里,我们保证1u,vn1 \leq u,v \leq n1≤u,v≤n。

接下来一行 333 个非负数 Q,K,SQ, K, SQ,K,S ,其中 QQQ 表示总天数,K0,1K \in {0,1}K∈0,1 是一个会在下面被用到的系数,SSS 表示的是可能的最高水位线。

接下来 QQQ 行依次描述每天的状况。每行 222 个整数 v0;p0v_0; p_0v0​;p0​ 描述一天:
这一天的出发节点为v=(v0+K×lastans1)modn+1v = (v_0 + K \times \mathrm{lastans} - 1) \bmod n + 1v=(v0​+K×lastans−1)modn+1。
这一天的水位线为p=(p0+K×lastans)mod(S+1)p = (p_0 + K \times \mathrm{lastans}) \bmod (S + 1)p=(p0​+K×lastans)mod(S+1)。
其中 lastans 表示上一天的答案(最小步行总路程)。特别地,我们规定第 111 天时 lastans = 0。 在这里,我们保证1v0n,0p0S1 \leq v_0 \leq n,0 \leq p_0 \leq S1≤v0​≤n,0≤p0​≤S 。

对于输入中的每一行,如果该行包含多个数,则用单个空格将它们隔开。

输出格式:

依次输出各组数据的答案。对于每组数据:

  • 输出 QQQ 行每行一个整数,依次表示每天的最小步行总路程。

输入输出样例

输入样例#1: 复制
1
4 3
1 2 50 1
2 3 100 2
3 4 50 1
5 0 2
3 0
2 1
4 1
3 1
3 2
输出样例#1: 复制
0
50
200
50
150
输入样例#2: 复制
1
5 5
1 2 1 2
2 3 1 2
4 3 1 2
5 3 1 2
1 5 2 1
4 1 3
5 1
5 2
2 0
4 0
输出样例#2: 复制
0
2
3
1

说明

【样例1 解释】 第一天没有降水,Yazid 可以坐车直接回到家中。

第二天、第三天、第四天的积水情况相同,均为连接1; 2 号节点的边、连接3; 4 号 点的边有积水。

对于第二天,Yazid 从2 号点出发坐车只能去往3 号节点,对回家没有帮助。因此 Yazid 只能纯靠徒步回家。

对于第三天,从4 号节点出发的唯一一条边是有积水的,车也就变得无用了。Yazid只能纯靠徒步回家。

对于第四天,Yazid 可以坐车先到达2 号节点,再步行回家。

第五天所有的边都积水了,因此Yazid 只能纯靠徒步回家。

本组数据强制在线。

本组数据强制在线。

第一天的答案是 000,因此第二天的 v=(5+01)mod5+1=5v=\left( 5+0-1\right)\bmod 5+1=5v=(5+0−1)mod5+1=5,p=(2+0)mod(3+1)=2p=\left(2+0\right)\bmod\left(3+1\right)=2p=(2+0)mod(3+1)=2。

第二天的答案是 222,因此第三天的 v=(2+21)mod5+1=4v=\left( 2+2-1\right)\bmod 5+1=4v=(2+2−1)mod5+1=4,p=(0+2)mod(3+1)=2p=\left(0+2\right)\bmod\left(3+1\right)=2p=(0+2)mod(3+1)=2。

第三天的答案是 333,因此第四天的 v=(4+31)mod5+1=2v=\left( 4+3-1\right)\bmod 5+1=2v=(4+3−1)mod5+1=2,p=(0+3)mod(3+1)=3p=\left(0+3\right)\bmod\left(3+1\right)=3p=(0+3)mod(3+1)=3。

所有测试点均保证 T3T\leq 3T≤3,所有测试点中的所有数据均满足如下限制:

  • n2×105n\leq 2\times 10^5n≤2×105,m4×105m\leq 4\times 10^5m≤4×105,Q4×105Q\leq 4\times 10^5Q≤4×105,K{0,1}K\in\left\{0,1\right\}K∈{0,1},1S1091\leq S\leq 10^91≤S≤109。
  • 对于所有边:l104l\leq 10^4l≤104,a109a\leq 10^9a≤109。
  • 任意两点之间都直接或间接通过边相连。

为了方便你快速理解,我们在表格中使用了一些简单易懂的表述。在此,我们对这些内容作形式化的说明:

  • 图形态:对于表格中该项为“一棵树”或“一条链”的测试点,保证m = n-1。 除此之外,这两类测试点分别满足如下限制:
  • 一棵树:保证输入的图是一棵树,即保证边不会构成回路。
  • 一条链:保证所有边满足u + 1 = v。
  • 海拔:对于表格中该项为“一种”的测试点,保证对于所有边有a = 1。
  • 强制在线:对于表格中该项为“是”的测试点,保证K = 1;如果该项为“否”, 则有K = 0。
  • 对于所有测试点,如果上述对应项为“不保证”,则对该项内容不作任何保证。
nnn mmm Q=Q=Q= 测试点 形态 海拔 强制在线
1\leq 1≤1 0\leq 0≤0 000 1 不保证 一种
6\leq 6≤6 10\leq 10≤10 101010 2 不保证 一种
50\leq 50≤50 150\leq 150≤150 100100100 3 不保证 一种
100\leq 100≤100 300\leq 300≤300 200200200 4 不保证 一种
1500\leq 1500≤1500 4000\leq 4000≤4000 200020002000 5 不保证 一种
200000\leq 200000≤200000 400000\leq 400000≤400000 100000100000100000 6 不保证 一种
1500\leq 1500≤1500 =n1=n-1=n−1 200020002000 7 一条链 不保证
1500\leq 1500≤1500 =n1=n-1=n−1 200020002000 8 一条链 不保证
1500\leq 1500≤1500 =n1=n-1=n−1 200020002000 9 一条链 不保证
200000\leq 200000≤200000 =n1=n-1=n−1 100000100000100000 10 一棵树 不保证
200000\leq 200000≤200000 =n1=n-1=n−1 100000100000100000 11 一棵树 不保证
200000\leq 200000≤200000 400000\leq 400000≤400000 100000100000100000 12 不保证 不保证
200000\leq 200000≤200000 400000\leq 400000≤400000 100000100000100000 13 不保证 不保证
200000\leq 200000≤200000 400000\leq 400000≤400000 100000100000100000 14 不保证 不保证
1500\leq 1500≤1500 4000\leq 4000≤4000 200020002000 15 不保证 不保证
1500\leq 1500≤1500 4000\leq 4000≤4000 200020002000 16 不保证 不保证
200000\leq 200000≤200000 400000\leq 400000≤400000 100000100000100000 17 不保证 不保证
200000\leq 200000≤200000 400000\leq 400000≤400000 100000100000100000 18 不保证 不保证
200000\leq 200000≤200000 400000\leq 400000≤400000 400000400000400000 19 不保证 不保证
200000\leq 200000≤200000 400000\leq 400000≤400000 400000400000400000 20 不保证 不保证

分析

显然找到不积水的连通块中的节点的最短路的最小值即可。最短路可以SPFADijkstra求,要干的就是找连通块。

把边按海拔从高到低排序,使用Kruskal重构树,这样连通块一定是一个子树,维护倍增的祖先和海拔最小值即可。

时间复杂度log级别。

加密算法要用到n的值,而我重构的时候直接++n了,所以一直错。找了好久才发现第二组样例都没有过。

co int N=4e5+1,INF=0x7fffffff;
int n,m,dis[N];
vector<pair<int,int> > g[N];
void dijkstra(){
	fill(dis+2,dis+n+1,INF);
	priority_queue<pair<int,int> > pq;
	pq.push(make_pair(-dis[1],1));
	while(pq.size()){
		int d=-pq.top().first,u=pq.top().second;pq.pop();
		if(d>dis[u]) continue;
		for(int i=0;i<g[u].size();++i){
			int v=g[u][i].first,w=g[u][i].second;
			if(d+w<dis[v]) dis[v]=d+w,pq.push(make_pair(-dis[v],v));
		}
	}
}

struct edge{int u,v,a;}e[N];
bool operator<(co edge&a,co edge&b) {return a.a>b.a;}
int fa[N];
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
int anc[N][20],val[N][20];
void kruskal(){
	sort(e+1,e+m+1);
	for(int i=1;i<=n;++i) fa[i]=i;
	for(int i=1,t=n;i<=m&&n<2*t-1;++i){
		int x=find(e[i].u),y=find(e[i].v);
		if(x==y) continue;
		++n,dis[n]=std::min(dis[x],dis[y]),anc[n][0]=val[n][0]=0;
		anc[x][0]=anc[y][0]=n,val[x][0]=val[y][0]=e[i].a;
		fa[n]=n,fa[x]=n,fa[y]=n;
	}
	for(int k=1;k<20;++k)
		for(int i=1;i<=n;++i){
			anc[i][k]=anc[anc[i][k-1]][k-1];
			val[i][k]=std::min(val[anc[i][k-1]][k-1],val[i][k-1]);
		}
}
int query(int v,int p){
	for(int k=19;k>=0;--k)
		if(val[v][k]>p) v=anc[v][k];
	return dis[v];
}

int main(){
	freopen("return.in","r",stdin),freopen("return.out","w",stdout);
	int kase=read<int>(),t;
	while(kase--){
		t=read(n),read(m); // edit 1:use n to decode
		for(int i=1;i<=n;++i) g[i].clear();
		for(int i=1,u,v,l;i<=m;++i){
			read(u),read(v),read(l);
			g[u].push_back(make_pair(v,l)),g[v].push_back(make_pair(u,l));
			e[i]=(edge){u,v,read<int>()};
		}
		dijkstra();
		kruskal();
		int Q=read<int>(),K=read<int>(),S=read<int>(),ans=0;
		for(int v,p;Q--;){
			v=(read<int>()+K*ans-1)%t+1,p=(read<ll>()+K*ans)%(S+1);
			printf("%d\n",ans=query(v,p));
		}
	}
	return 0;
}

标签:200000,ICPC2021,int,400000,Life,leq,Game,保证,1500
来源: https://www.cnblogs.com/autoint/p/16575728.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有