Codeforces 487E Tourists

本文介绍了一种利用Tarjan算法进行缩点,并结合树剖技术解决图上最值查询与更新问题的方法。通过新建节点表示强连通分量,并采用高级建图策略,实现了高效的点权值查询与修改。

题意:给出一幅图和每个点的权值,每次修改某个点权值或询问两点间所有简单路径上的点权值最小值

思路:

只能看出来tarjan缩点和树剖,然后完全未考虑清楚细节。。似乎建图方法很高级

首先tarjan缩点,对于每个块,新建一个点x,x向所有块内不是深度最小的点连边(借鉴(抄袭)某神犇的方法),然后深度最小的点向x连边,然后x的权值为所有块内不是深度最小的点的权值的最小值,然后询问时如果lca是新建点(序号>n)那就还要跟其父亲节点权值取min,修改时也要修改父亲节点(必定为新建点)的值,然后每个新建点可以用multiset(第一次用,好高级)维护块内(除掉某个点)的最小值。。

注意缩点姿势比较神奇(深度最小的点不要退栈啊!)

代码:

#include <bits/stdc++.h>
#define gc getchar()
#define N 200009
#define M 200009
#define mid (l+r>>1)
#define root 1,1,cnt
#define lson cur<<1,l,mid
#define rson cur<<1|1,mid+1,r
#define lc cur<<1
#define rc cur<<1|1
using namespace std;
typedef multiset<int>::iterator ptr;
int n,m,Q,x,y,first[N],number=1;
int Number,First[N<<1],rt;
int top,cnt,taj,vis[N<<1],size[N<<1];
int num[N<<1],deep[N<<1],Top[N<<1],father[N<<1],Mson[N<<1];
int dfn[N<<1],low[N],sta[M],val[N],Id[N];
int v[N<<3];
multiset<int> q[N<<3];
struct edge
{
	int from,to,next;
	void add(int x,int y)
	{
		from=x,to=y,next=first[x],first[x]=number;
	}
}e[N<<1];
struct Edge
{
	int to,next;
	void add(int x,int y)
	{
		to=y,next=First[x],First[x]=Number;
	}
}E[N<<3];
int read()
{
	int x=1;
	char ch;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	int s=ch-48;
	while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
	return x*s;
}
void tarjan(int x)
{
	dfn[x]=low[x]=++cnt;
	sta[++top]=x;
	for (int i=first[x];i;i=e[i].next)
		if (!dfn[e[i].to])
		{
			tarjan(e[i].to);
			low[x]=min(low[x],low[e[i].to]);
			if (low[e[i].to]>=dfn[x])
			{
				++taj;
				father[taj]=x;
				E[++Number].add(x,taj);
				do
				{
					y=sta[top--];
					father[y]=taj;
					E[++Number].add(taj,y);
					q[taj].insert(val[y]);
				}while (y!=e[i].to);
			}
		}
		else low[x]=min(low[x],dfn[e[i].to]);
}
void dfs1(int x)
{
	size[x]=1;
	deep[x]=deep[father[x]]+1;
	for (int i=First[x];i;i=E[i].next)
	{
		dfs1(E[i].to);
		size[x]+=size[E[i].to];
		if (size[E[i].to]>size[Mson[x]]) Mson[x]=E[i].to;
	}
}
void dfs2(int x,int y)
{
	Top[x]=y;
	dfn[x]=++cnt;
	Id[cnt]=x;
	if (Mson[x]) dfs2(Mson[x],y);
	for (int i=First[x];i;i=E[i].next)
		if (E[i].to!=Mson[x]) dfs2(E[i].to,E[i].to);
}
void build(int cur,int l,int r)
{
	if (l==r)
	{
		v[cur]=val[Id[l]];
		return;
	}
	build(lson);
	build(rson);
	v[cur]=min(v[lc],v[rc]);
}
void ins(int cur,int l,int r,int x,int y)
{
	if (l==r)
	{
		v[cur]=y;
		return;
	}
	if (x<=mid) ins(lson,x,y);
	else ins(rson,x,y);
	v[cur]=min(v[lc],v[rc]);
}
int qry(int cur,int l,int r,int L,int R)
{
	if (L<=l&&R>=r) return v[cur];
	int ans=1000000000;
	if (L<=mid) ans=min(ans,qry(lson,L,R));
	if (R>mid) ans=min(ans,qry(rson,L,R));
	return ans;
}
int qry(int x,int y)
{
	int ans=1000000000;
	for (;Top[x]!=Top[y];x=father[Top[x]])
	{
		if (deep[Top[x]]<deep[Top[y]]) swap(x,y);
		ans=min(ans,qry(root,dfn[Top[x]],dfn[x]));
	}
	if (dfn[x]>dfn[y]) swap(x,y);
	ans=min(ans,qry(root,dfn[x],dfn[y]));
	int lca=(dfn[x]<dfn[y])?x:y;
	if (lca>n) ans=min(ans,val[father[lca]]);
	return ans;
}
int getroot(int x)
{
	return father[x]?getroot(father[x]):x;
}
int main()
{
	memset(First,0,sizeof(First));
	n=read(),m=read(),Q=read();
	for (int i=1;i<=n;i++) val[i]=read();
	for (int i=1;i<=m;i++)
	{
		x=read(),y=read();
		e[++number].add(x,y),e[++number].add(y,x);
	}
	taj=n;
	tarjan(1);
	memset(dfn,0,sizeof(dfn));
	cnt=0;
	rt=getroot(1);
	dfs1(rt);
	dfs2(rt,rt);
	for (int i=n+1;i<=taj;i++)
		val[i]=*q[i].begin();
	build(root);
	for (int i=1;i<=Q;i++)
	{
		char ch;
		while (ch=gc,ch!='A'&&ch!='C');
		x=read(),y=read();
		if (ch=='C')
		{
			if (father[x])
				q[father[x]].erase(q[father[x]].find(val[x]));
			ins(root,dfn[x],y);
			val[x]=y;
			if (father[x])
			{
				q[father[x]].insert(y);
				val[father[x]]=*q[father[x]].begin();
				ins(root,dfn[father[x]],val[father[x]]);
			}
		}
		else printf("%d\n",qry(x,y));
	}
	return 0;
}


### Codeforces 887E Problem Solution and Discussion The problem **887E - The Great Game** on Codeforces involves a strategic game between two players who take turns to perform operations under specific rules. To tackle this challenge effectively, understanding both dynamic programming (DP) techniques and bitwise manipulation is crucial. #### Dynamic Programming Approach One effective method to approach this problem utilizes DP with memoization. By defining `dp[i][j]` as the optimal result when starting from state `(i,j)` where `i` represents current position and `j` indicates some status flag related to previous moves: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = ...; // Define based on constraints int dp[MAXN][2]; // Function to calculate minimum steps using top-down DP int minSteps(int pos, bool prevMoveType) { if (pos >= N) return 0; if (dp[pos][prevMoveType] != -1) return dp[pos][prevMoveType]; int res = INT_MAX; // Try all possible next positions and update 'res' for (...) { /* Logic here */ } dp[pos][prevMoveType] = res; return res; } ``` This code snippet outlines how one might structure a solution involving recursive calls combined with caching results through an array named `dp`. #### Bitwise Operations Insight Another critical aspect lies within efficiently handling large integers via bitwise operators instead of arithmetic ones whenever applicable. This optimization can significantly reduce computation time especially given tight limits often found in competitive coding challenges like those hosted by platforms such as Codeforces[^1]. For detailed discussions about similar problems or more insights into solving strategies specifically tailored towards contest preparation, visiting forums dedicated to algorithmic contests would be beneficial. Websites associated directly with Codeforces offer rich resources including editorials written after each round which provide comprehensive explanations alongside alternative approaches taken by successful contestants during live events. --related questions-- 1. What are common pitfalls encountered while implementing dynamic programming solutions? 2. How does bit manipulation improve performance in algorithms dealing with integer values? 3. Can you recommend any online communities focused on discussing competitive programming tactics? 4. Are there particular patterns that frequently appear across different levels of difficulty within Codeforces contests?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值