【NOI2018模拟4.4】Map

2024-05-29 02:48
文章标签 模拟 map 4.4 noi2018

本文主要是介绍【NOI2018模拟4.4】Map,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

Rin是个特别好动的少女。
一天Rin来到了一个遥远的都市。这个都市有N个建筑,编号从1到N,其中市中心编号为1,这个都市有M条双向通行的街道,每条街道连接着两个不同的建筑,其中某些街道首尾相连连接成了一个环。Rin通过长时间的走访,已经清楚了这个都市的两个特点:
从市中心出发可以到达所有的建筑物。
任意一条街道最多存在与一个简单环中。令Rin心花怒放的是,每个建筑物都会有拉面售卖。拉面有很多不同的种类,但对于Rin而言只有油腻程度的不同,因此我们把油腻程度相同的拉面看做同一种拉面。由于不同建筑物的拉面的油腻程度可能不同,我们用一个正整数来表示拉面的油腻程度。
要知道,拉面可是Rin的最爱,但是现在到了下班高峰期,都市的交通变得非常的堵塞。Rin只能通过没有被堵死的街道通行,去品尝所在建筑物的拉面。
现在Rin想知道,如果她正在编号为x的建筑物,那么在从市中心到x的所有简单路径经过的街道都被堵死的情况下,Rin可以品尝到的拉面中(注意没有出现的拉面是不能算在里面的):
油腻程度<=y且品尝次数为奇数次的拉面有多少种?
油腻程度<=y且品尝次数为偶数次的拉面有多少种?

Input

第一行两个正整数N,M,含义如题所示。
第二行一共N个正整数,第i个数Ai表示第i个建筑物出售的拉面的油腻程度。
接下来M行,每行两个正整数x,y,表示在建筑物x,y之间有一条双向通行的街道。数据保证1<=x,y<=N。
接下来一行一个正整数Q,表示询问个数。
接下来Q行每行三个非负整数ty,x,y,x表示询问的建筑物编号,y表示油腻程度的限制,ty=0时表示询问偶数,ty=1表示询问奇数。

Output

一共q行,对于每个询问输出一个答案。

Sample Input

5 6
2 1 6 7 7
1 2
1 3
2 4
4 5
4 5
1 3
3
0 3 2
0 3 1
0 1 7

Sample Output

0
0
1

Data Constraint

这里写图片描述

Solution

仙人掌,有一种套路变成树:详细点这里查看
大概就是弄出环顶,把环上的点连到环顶上。这样和树就完全相同了。
树怎么做呢?
对于每个点,开一个线段树表示每个点的每种拉面偶数次和奇数次的有多少种,维护很简单,线段树合并一下就行了。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 101000
using namespace std;
int n,m,a[N],last[N],nxt[N*5],to[N*5],tot=1,fa[N],dfn[N],s[N],K;
int root[N],q[N][3],las[N],xnt[N],dat[N],son[N],sz[N],ans[N],b[N],c[N],d[1010000],qu;
struct node{int l,r,d1,d2;
}t[N*70];
void putin(int x,int y)
{nxt[++tot]=last[x];last[x]=tot;to[tot]=y;
}
void putsin(int x,int y)
{xnt[++tot]=las[x];las[x]=tot;dat[tot]=y;
}
bool cnt(int x,int y){return c[x]<c[y];}
void tarjan(int x,int fat)
{dfn[x]=++tot;s[++s[0]]=x;for(int i=last[x];i;i=nxt[i])if(i!=fat){int y=to[i];if(dfn[y]>0){if(dfn[y]<dfn[x]) for(int z=s[0];s[z]!=y;z--) fa[s[z]]=y;continue;}tarjan(y,i^1);if(fa[y]==0) fa[y]=x;}s[0]--;
}
void dg(int x)
{sz[x]=1;for(int i=last[x];i;i=nxt[i]){int y=to[i];dg(y);sz[x]+=sz[y];if(sz[y]>sz[son[x]]) son[x]=y;}
}
void add(int &x)
{if(x>0) return;x=++tot;
}
void update(int v)
{t[v].d1=t[t[v].l].d1+t[t[v].r].d1;t[v].d2=t[t[v].l].d2+t[t[v].r].d2;
}
void merge(int v1,int v2,int i,int j)
{if(i==j){int x=t[v1].d1^t[v2].d1;if(x==0) t[v1].d1=1,t[v1].d2=0;else t[v1].d1=0,t[v1].d2=1;return;}int m=(i+j)/2;if(t[v1].l==0) t[v1].l=t[v2].l;else if(t[v2].l>0) merge(t[v1].l,t[v2].l,i,m);if(t[v1].r==0) t[v1].r=t[v2].r;else if(t[v2].r>0) merge(t[v1].r,t[v2].r,m+1,j);update(v1);}
void change(int v,int i,int j,int x)
{if(i==j){if(t[v].d1+t[v].d2==0) t[v].d2=1;else t[v].d1=1-t[v].d1,t[v].d2=1-t[v].d2;return;}int m=(i+j)/2;if(x<=m) add(t[v].l),change(t[v].l,i,m,x);else add(t[v].r),change(t[v].r,m+1,j,x);update(v);
}
int get(int v,int i,int j,int x,int y,int z)
{if(v==0) return 0;if(i==x&&j==y){if(z==0) return t[v].d1;else return t[v].d2;}int m=(i+j)/2;if(y<=m) return get(t[v].l,i,m,x,y,z);else if(x>m) return get(t[v].r,m+1,j,x,y,z);else return get(t[v].l,i,m,x,m,z)+get(t[v].r,m+1,j,m+1,y,z);
}
void dfs(int x)
{if(son[x]>0){dfs(son[x]);root[x]=root[son[x]];}else root[x]=++tot;for(int i=last[x];i;i=nxt[i]){int y=to[i];if(y==son[x]) continue;dfs(y);merge(root[x],root[y],1,K);}change(root[x],1,K,a[x]);for(int i=las[x];i;i=xnt[i]){int y=dat[i];if(q[y][2]>c[b[n]]) d[q[y][2]]=K;if(d[q[y][2]]>0) ans[y]=get(root[x],1,K,1,d[q[y][2]],q[y][0]);}
}
int main()
{freopen("map.in","r",stdin);freopen("map.out","w",stdout);scanf("%d%d",&n,&m);fo(i,1,n) scanf("%d",&c[i]),b[i]=i;sort(b+1,b+n+1,cnt);fo(i,1,n){if(c[b[i]]>c[b[i-1]]) K++;fo(j,c[b[i-1]],c[b[i]]-1) d[j]=K-1;a[b[i]]=K;}d[c[b[n]]]=K;fo(i,1,m){int x,y;scanf("%d%d",&x,&y);putin(x,y);putin(y,x);}tot=0;tarjan(1,0);memset(last,0,sizeof(last));tot=0;fo(i,2,n) putin(fa[i],i);dg(1);tot=0;scanf("%d",&qu);fo(i,1,qu){scanf("%d%d%d",&q[i][0],&q[i][1],&q[i][2]);putsin(q[i][1],i);}tot=0;dfs(1);fo(i,1,qu) printf("%d\n",ans[i]);
}

这篇关于【NOI2018模拟4.4】Map的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1012430

相关文章

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

hdu4431麻将模拟

给13张牌。问增加哪些牌可以胡牌。 胡牌有以下几种情况: 1、一个对子 + 4组 3个相同的牌或者顺子。 2、7个不同的对子。 3、13幺 贪心的思想: 对于某张牌>=3个,先减去3个相同,再组合顺子。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOExcepti

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

Collection List Set Map的区别和联系

Collection List Set Map的区别和联系 这些都代表了Java中的集合,这里主要从其元素是否有序,是否可重复来进行区别记忆,以便恰当地使用,当然还存在同步方面的差异,见上一篇相关文章。 有序否 允许元素重复否 Collection 否 是 List 是 是 Set AbstractSet 否

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

【算法专场】模拟(下)

目录 前言 38. 外观数列 算法分析 算法思路 算法代码 1419. 数青蛙 算法分析 算法思路 算法代码  2671. 频率跟踪器 算法分析 算法思路 算法代码 前言 在前面我们已经讲解了什么是模拟算法,这篇主要是讲解在leetcode上遇到的一些模拟题目~ 38. 外观数列 算法分析 这道题其实就是要将连续且相同的字符替换成字符重复的次数+

模拟实现vector中的常见接口

insert void insert(iterator pos, const T& x){if (_finish == _endofstorage){int n = pos - _start;size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);pos = _start + n;//防止迭代

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT

1 模拟——67. 二进制求和

1 模拟 67. 二进制求和 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1:输入:a = "11", b = "1"输出:"100"示例 2:输入:a = "1010", b = "1011"输出:"10101" 算法设计 可以从低位到高位(从后向前)计算,用一个变量carry记录进位,如果有字符没处理完或者有进位,则循环处理。两个字符串对