4月4号 题目分享

NEKO#ΦωΦ has just got a new maze game on her PC!

The game’s main puzzle is a maze, in the forms of a 2×n rectangle grid. NEKO’s task is to lead a Nekomimi girl from cell (1,1) to the gate at (2,n) and escape the maze. The girl can only move between cells sharing a common side.

However, at some moments during the game, some cells may change their state: either from normal ground to lava (which forbids movement into that cell), or vice versa (which makes that cell passable again). Initially all cells are of the ground type.

After hours of streaming, NEKO finally figured out there are only q such moments: the i-th moment toggles the state of cell (ri,ci) (either from ground to lava or vice versa).

Knowing this, NEKO wonders, after each of the q moments, whether it is still possible to move from cell (1,1) to cell (2,n) without going through any lava cells.

Although NEKO is a great streamer and gamer, she still can’t get through quizzes and problems requiring large amount of Brain Power. Can you help her?

INPUT

The first line contains integers n, q (2≤n≤105, 1≤q≤105).

The i-th of q following lines contains two integers ri, ci (1≤ri≤2, 1≤ci≤n), denoting the coordinates of the cell to be flipped at the i-th moment.

It is guaranteed that cells (1,1) and (2,n) never appear in the query list.

OUTPUT

For each moment, if it is possible to travel from cell (1,1) to cell (2,n), print “Yes”, otherwise print “No”. There should be exactly q answers, one after every update.

You can print the words in any case (either lowercase, uppercase or mixed).

EXAMPLE

Input
5 5
2 3
1 4
2 4
2 3
1 4
Output
Yes
No
No
No
Yes

翻译成人话:

题目大意:给出n个数,m个操作。输入a,b,a为操作种类,b为操作位置。
2种操作——1.1到b从小到大排序,2.从1到b从大到小排序。最后输出最终操作后的数组。
I:2*n的迷宫,从(1,1)出发到(2,n),初始时全部的都是地面,每次询问会把一个地面给变成熔浆,熔浆变成地面,熔浆不能通过,问是否可以走到。

从头到尾遍历肯定是不现实的,实际上也不需要,直接记录道路中间的断路即可:
在这里插入图片描述
如图,一开始的图肯定是能走到的,所以我们每读入一个操作(如图中的蓝绿色块),就判断一下对面的三个能不能过,一旦有一个不能过,就无法到达尾部,而且这个影响是可以叠加的,具体如下

int Ok(int x){
	if(x==1) return 2;
	else return 1;
}
int Check(int x,int y){
	if(a[x][y]==0){
		for(int i=y-1;i<=y+1;i++)
			if(a[Ok(x)][i]) cnt++;
	}
	else{
		for(int i=y-1;i<=y+1;i++)
			if(a[Ok(x)][i]) cnt--;
	}
	a[x][y]=!a[x][y];
	return cnt;
	//cnt是一个全局变量,记录全图中一共多少个断点
}

第二题

题目传送门:洛谷6082

先直接看代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1e5+10;
int dp[maxn],w[maxn],cnt[maxn],son[maxn];
bool check[maxn];
int n;
int head[maxn],len=0;
struct Edge{
	int next,to;
}edge[maxn<<1];
void Add(int u,int v){
	edge[++len].to=v;
	edge[len].next=head[u];
	head[u]=len;
}
bool Cmp(int a,int b){
	return dp[a]>dp[b];
}
void dfs(int u,int fa){
	dp[u]=w[u];
	int tot=0;
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==fa) continue;
		 dfs(v,u);
	}
	for(int i=head[u];i;i=edge[i].next){ //这里是必须要开两遍for循环的,因为我们经过一轮dfs后儿子才能变成有序的
		int v=edge[i].to;
		if(v==fa) continue;
		son[++tot]=v;
	}
	sort(son+1,son+1+tot,Cmp);
	int p=0;
	while(p<min(cnt[u]-1,tot)&&dp[son[p+1]]>=0){
		dp[u]+=dp[son[++p]];
		check[u]|=check[son[p]];
	}
	if(p<tot&&p>0&&dp[son[p]]==dp[son[p+1]]||dp[son[p]]==0&&p>0)
		check[u]=1;
}
int main(){
	cin>>n;
	w[1]=0;
	for(int i=2;i<=n;i++)
		scanf("%d",&w[i]);
	for(int i=2;i<=n;i++)
		scanf("%d",&cnt[i]);
	for(int i=1;i<=n-1;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		Add(u,v),Add(v,u);
	}
	cnt[1]=n+1; //我一开始以为cnt[1]是与1相连的节点的个数,结果GG,发现在一定情况下可以好几次回到1,所以cnt[1]应该是无限大的,这里直接n+1效果是一样的
	dfs(1,0);
	printf("%d
",dp[1]);
	if(check[1])
		cout<<"solution is not unique"<<endl;
	else
		cout<<"solution is unique"<<endl;
	return 0;
}

实际上这题就是贪心,因为我们每个节点能到达的次数有限,所以我们一旦到了这个节点,下一步肯定往价值大的那个儿子那里走,所以我们先dfs一遍后再给儿子们排一下序就好,注意我们一定要留出一次停留机会来,因为我们最后要回家呀!

另外一个要点是判断是否有重复的方案,思路很明朗:如果有一个节点儿子的价值里有相同的,那我们肯定走哪个都行,所以这样方案是重的;另外如果是有一个儿子价值是零,那我们走不走都行,这样方案也是重的

综上,此题就没什么别的东西了!

$$We're ; here ; to ; put ; a ; dent ; in ; the ; universe.$$
原文地址:https://www.cnblogs.com/Zfio/p/12749662.html