首页 > 其他分享 >Educational Codeforces Round 138 E,F

Educational Codeforces Round 138 E,F

时间:2022-11-05 23:03:16浏览次数:90  
标签:std nxt Educational int 路径 Codeforces pos 138 id

E
一道比较基础的题。

首先就是纵向,走无障碍的格子,无法四联通横向,走有障碍的格子,八联通是等价的。

也就是,如果我们要让其不存在非法路径,那么应该存在一个从第一列出发,一路都是#的八联通路径,并且根据题意,仙人掌不能上下左右相邻,那么就是右上、右下、左上、左下的四个方向的路径。

那么我们可以在某些点将'.'换成'#'(注意这个点四周不能有'#'),并且“路径”长度加一。

也就是可以01 BFS解决。

F
一道十分有趣的题。

首先我们直接找所有距离路径不超过\(d\)的点是没戏的。

考虑只更新链。在查询时,我们从当前点\(x\)一路往上跳,并且将\(d\)从\(0\)一路相加到\(20\)为止。

更新时,我们要给路径上每个点在一个下标处\(+k\),使得查询时没有重复计算。

所以,我们能构造出下图左侧的方法,也就是\(x\)到\(y\)路径上的tag为\(d\),\(lca\)往上分别是\(d-1\)到\(0\)。

但是我们发现一个问题,比如中间的情况,我们查询(红线)往上跳时,正好“错过”了我们修改,也就是交点在两个节点中间,这种情况会出现漏统计。

不过很幸运,只有这一种情况会出错。

于是我们稍作修改,得到右侧的打\(tag\)方式,就是对于\(lca\)和往上的点,分别将\(i\)和\(i-1\)加入,这样就不用担心交点在中间了,并且其余的路径交点个数也是\(1\)。

可以用树链剖分进行路径修改,时间复杂度为\(O(n(\log n+d)\log n)\)。

这里附上两题代码:
E

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=400005;

const int dx[]={-1,1,1,-1,0,0,-1,1};
const int dy[]={1,-1,1,-1,-1,1,0,0};

int n,m,dist[maxn],from[maxn],vis[maxn],cant[maxn];
char buf[maxn];
std::vector<std::pair<int,int>> G[maxn];

int main() {
	int T;
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&m);
		std::vector<int> a(1,0);
		std::vector<std::vector<int>> id(n+5,std::vector<int>(m+5,0));
		for(int i=1;i<=n;i++) {
			scanf("%s",buf+1);
			for(int j=1;j<=m;j++) {
				id[i][j]=a.size();
				a.push_back(buf[j]=='#'?1:0);
			}
		}
		for(int i=1;i<=n*m;i++) {
			G[i].clear();
			cant[i]=0;
		}
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				if(a[id[i][j]]==1) {
					for(int k=4;k<8;k++) {
						int i_=i+dx[k],j_=j+dy[k];
						if(i_<1||j_<1||i_>n||j_>m) continue;
						cant[id[i_][j_]]=1;
					}
				}
			}
		}
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				if(cant[id[i][j]]) continue;
				for(int k=0;k<4;k++) {
					int i_=i+dx[k],j_=j+dy[k];
					if(i_<1||j_<1||i_>n||j_>m||cant[id[i_][j_]]) continue;			
					G[id[i][j]].push_back({id[i_][j_],1-a[id[i_][j_]]});
				}
			}
		}
		std::deque<int> q;
		for(int i=1;i<=n*m;i++) dist[i]=1e9,from[i]=-1,vis[i]=0;
		for(int i=1;i<=n;i++) {
			if(a[id[i][1]]) q.push_front(id[i][1]),dist[id[i][1]]=0;
			else q.push_back(id[i][1]),dist[id[i][1]]=1;
		}
		while(!q.empty()) {
			int pos=q.front(); q.pop_front();
			if(vis[pos]) continue;
			vis[pos]=1;
			for(auto nxt : G[pos]) {
				if(dist[nxt.first]>dist[pos]+nxt.second) {
					dist[nxt.first]=dist[pos]+nxt.second;
					from[nxt.first]=pos;
					if(nxt.second) q.push_back(nxt.first);
					else q.push_front(nxt.first);
				}
			}
		}
		int start=-1,ans=1e9;
		for(int i=1;i<=n;i++) {
			if(dist[id[i][m]]<ans) {
				ans=dist[id[i][m]];
				start=id[i][m];
			}
		}
		if(ans==1e9) {
			printf("NO\n");
			continue;
		}
		printf("YES\n");
		while(start!=-1) {
			if(!a[start]) a[start]=1;
			start=from[start];
		}
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				printf("%c",a[id[i][j]]?'#':'.');
			}
			printf("\n");
		} 
	} 
	return 0;
}

F

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=200105;

int n,q;
int cnt,id[maxn],siz[maxn],son[maxn],top[maxn],father[maxn],dep[maxn];
std::vector<int> G[maxn];

void dfs(int pos,int fa,int depth) {
	siz[pos]=1,father[pos]=fa,dep[pos]=depth;
	for(int i=0,temp=-1;i<(int)G[pos].size();i++) {
		int to=G[pos][i]; if(to==fa) continue;
		dfs(to,pos,depth+1); siz[pos]+=siz[to];
		if(siz[to]>temp) temp=siz[to],son[pos]=to;
	}
}
 
void dfs2(int pos,int fa,int tp) {
	id[pos]=++cnt; top[pos]=tp;
	if(son[pos]) dfs2(son[pos],pos,tp);
	for(int i=0;i<(int)G[pos].size();i++) {
		int to=G[pos][i];
		if(to!=fa&&to!=son[pos]) dfs2(to,pos,to);
	}
}

struct bit {
	int val[maxn];
	#define lowbit(x) (x&-x)
	void update(int l,int r,int num) {
		for(int i=l;i<maxn;i+=lowbit(i)) val[i]+=num;
		for(int i=r+1;i<maxn;i+=lowbit(i)) val[i]-=num;
	}
	int query(int x) {
		int ret=0;
		for(int i=x;i;i-=lowbit(i)) ret+=val[i];
		return ret;
	}
}tree[25];

void upath(int x,int y,int num,int d) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
		tree[d].update(id[top[x]],id[x],num);
		x=father[top[x]];
	}
	if(dep[x]>dep[y]) std::swap(x,y);
	tree[d].update(id[x]+1,id[y],num);
	for(;d>=0;d--,x=father[x]) {
		tree[d].update(id[x],id[x],num);
		if(d) tree[d-1].update(id[x],id[x],num);
	}
}

int qnode(int x) {
	int ans=0;
	for(int d=0;d<=20;d++,x=father[x]) {
		ans+=tree[d].query(id[x]);
	}
	return ans;
}

int main() {
	scanf("%d",&n);
	for(int i=1;i<n;i++) {
		int x,y; scanf("%d%d",&x,&y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	int root=n+25;
	G[n+1].push_back(1);
	G[1].push_back(n+1);
	for(int i=n+2;i<=n+30;i++) {
		G[i].push_back(i-1);
		G[i-1].push_back(i);
	}
	//root
	dfs(root,0,1); dfs2(root,0,root);
	scanf("%d",&q);
	while(q--) {
		int opt,x,y,k,d;
		scanf("%d",&opt);
		if(opt==1) {
			scanf("%d",&x);
			printf("%d\n",qnode(x));
			
		} else {
			scanf("%d%d%d%d",&x,&y,&k,&d);
			upath(x,y,k,d);
		}
	}
	return 0;
}

标签:std,nxt,Educational,int,路径,Codeforces,pos,138,id
From: https://www.cnblogs.com/Nastia/p/16861599.html

相关文章

  • Educational Codeforces Round 118 D
    D.MEXSequences对于一个数x要是前面出现过0,1,2...x-1我们显然可以将他放在后面要是前面出现过012...x-1x我们也可以将他放在后面但是观察样例还有一种情况......
  • Codeforces Round #826 (Div. 3) D. Masha and a Beautiful Tree(树+dfs)
    D.MashaandaBeautifulTree题目大意:给定一颗满二叉树的叶子节点,让我们更换子树位置,从而让叶子节点排序为升序求最小操作数,如果不能移动成那样的话,直接输出-1.in......
  • Codeforces 杂题记录
    CF1753A2(调整、贪心)考虑钦定\([1,n]\)分成一段,调整就是把贡献取相反数。CF1753B每次把\((i+1)\)和\(i!\)合并成一个\((i+1)!\),看能不能合并到\(x!\)。CF1753C(......
  • Codeforces Round #832 (Div. 2) C. Swap Game (博弈论)
    https://codeforces.com/contest/1747/problem/CC.SwapGame题目大意:给定一个长度为n的数组a,每次只要当我想动但是发现a[1]==0的时候我就输了要么就是我每次把a[1]......
  • 「题解」Codeforces 1612F Armor and Weapons
    首先可以不管套件,假定\(n<m\),那么答案不超过\(\mathcal{O}(\logn+\frac{m}{n})\),也就是先倍增把\(n\)造出来,然后一步步造\(m\).答案这么小,那么常见的套路就是把答案......
  • Codeforces Round #832 (Div2)
    A.TwoGruops将正负数分离为两个集合,得到\(sum_{+},sum_{-}\)。考虑将一个数移到正负性相反的集合中,一定会导致\(sum_{+},sum_{-}\)同时在数轴上向原点移动,差值绝对......
  • Codeforces Round #832 (Div. 2) E
    牛逼题。通过拐点刻画路径,这样每条路径的贡献方式唯一,你只要钦定拐点都选即可刻画唯一的路径,然后路径上的其他点随便选。https://codeforc.es/contest/1747/problem/Eht......
  • Codeforces Round #751 (Div. 2) D
    D.FrogTraveler考虑dpdp[i]表示i高度的时候最少多少步能达到然后再bfs就可以了但是这样是n2的虽然看起来只有n个点我们考虑优化我们主要复杂度是当前点还会去搜......
  • Codeforces Round #832 (Div. 2) A-D
    比赛链接A题解知识点:贪心。我们考虑把正数和负数分开放,显然把负数和正数放在一起的结果不会更优。时间复杂度\(O(n)\)空间复杂度\(O(1)\)代码#include<bits/std......
  • Codeforces Round #832 (Div. 2)
    A.TwoGroups数组和的绝对值即为答案。B.BANBAN大概就是尽可能把前面的B搞到后面,尽可能把后面的N搞到前面。答案为\(\lceil\frac{n}{2}\rceil\),操作为每次......