【2020五校联考NOIP #7】伟大的卫国战争
题面传送门
题意:
数轴上有 \(n\) 个点,现在要在它们之间连 \(m\) 条边,第 \(i\) 条边连接 \(a_i,b_i\) 两个点。
现在你要钦定每条边连在数轴的上方还是下方,使得任意两条边要么不相交,要么只在线段顶点处相交;或者宣告无解。
注:两条边 \((l_1,r_1),(l_2,r_2)\) 的条件是 \(l_1<l_2<r_1,r_2>r_1\) 或 \(l_1<r_2<r_1,l_2<l_1\)。
\(n,m \in [1,10^5]\)。
话说这题出现了两次呢……
容易想到 \(m^2\) 的做法,你在任意两条相交的区间之间连一条无向边。然后对此图进行二分图染色。
那么,二分图染色是不是就没有前途了呢?
细心观察,我们连边形成的图中,点的个数并不多,总共只有 \(m\) 个点,瓶颈在于边的个数很多。
回忆起之前学习二分图染色时的一个性质:对于一个连通块,如果可以进行二分图染色,那么染色方案也就唯一确定下来了。
根据这个性质,我们可以想到一个做法:每个连通块,给出一个可能的染法,然后回过头来判断这个染法是否可行。
那么具体该怎样进行染色呢?
访问区间 \(i\) 的时候,用线段树求出所有与 \(i\) 相交的区间 \(j\)。将这些区间全部从线段树删除。并对它们进行 dfs。
由于 \(i\) 与 \(j\) 相交,\(j\) 与 \(i\) 一定不能染相同的颜色。
继续这样 dfs 下去就可以染好一整个连通块。
这个做法看似与之前没什么两样,不过注意到每个点最多只会被取出一次,访问一次,所以总复杂度只有 \(m \log m\)。
怎样用线段树维护这些区间呢?我们建两棵线段树,一棵以右端点为下标,另一棵以左端点为下标,分别维护上述两种情况。
这里以右端点为例。叶子节点 \(r\) 为右端点为 \(r\) 的区间。区间按左端点从小到大排序。
查找 \(l_1<r_2<r_1,l_2<l_1\) 的区间的时候,不断取出 \([l_1+1,r_1-1]\) 的最小区间并将其删除,直到最小区间的左端点 \(\geq r_1\)。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
typedef pair<int,int> pii;
typedef long long ll;
const int SEGTREE_MIN=376;
const int SEGTREE_MAX=377;
const pii INF=make_pair(0x3f3f3f3f,0x3f3f3f3f);
const pii ZERO=make_pair(0,0);
int n,m,a[100005],b[100005];
struct segtree_pii{
int op;
struct node{
int l,r;
pii val;
} s[100005<<2];
multiset<pii> st[100005];
inline void build(int k,int l,int r){
if(op==SEGTREE_MIN) s[k].val=INF;else s[k].val=ZERO;
s[k].l=l;s[k].r=r;if(l==r) return;
int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline pii query(int k,int l,int r){
if(l>r){
if(op==SEGTREE_MIN) return INF;
else return ZERO;
}
if(l<=s[k].l&&s[k].r<=r) return s[k].val;
int mid=(s[k].l+s[k].r)>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else{
if(op==SEGTREE_MIN) return min(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
}
inline void push(int k,int ind,pii x){
if(s[k].l==s[k].r){
st[s[k].l].insert(x);
if(op==SEGTREE_MIN) s[k].val=*st[s[k].l].begin();
else s[k].val=*st[s[k].l].rbegin();
return;
}
int mid=(s[k].l+s[k].r)>>1;
if(ind<=mid) push(k<<1,ind,x);
else push(k<<1|1,ind,x);
if(op==SEGTREE_MIN) s[k].val=min(s[k<<1].val,s[k<<1|1].val);
else s[k].val=max(s[k<<1].val,s[k<<1|1].val);
}
inline void pop(int k,int ind,pii v){
if(s[k].l==s[k].r){
st[s[k].l].erase(st[s[k].l].find(v));
if(op==SEGTREE_MIN){
if(!st[s[k].l].empty()) s[k].val=*st[s[k].l].begin();
else s[k].val=INF;
}
else{
if(!st[s[k].l].empty()) s[k].val=*st[s[k].l].rbegin();
else s[k].val=ZERO;
}
return;
}
int mid=(s[k].l+s[k].r)>>1;
if(ind<=mid) pop(k<<1,ind,v);
else pop(k<<1|1,ind,v);
if(op==SEGTREE_MIN) s[k].val=min(s[k<<1].val,s[k<<1|1].val);
else s[k].val=max(s[k<<1].val,s[k<<1|1].val);
}
} l,r;
map<pair<int,int>,int> id;
int col[100005];
inline void dfs(int x){
// printf("%d\n",x);
vector<int> todo;
pii v=l.query(1,a[x]+1,b[x]-1);
while(v.fi<a[x]){
// printf("%d %d\n",v.fi,v.se);
int j=id[make_pair(v.fi,v.se)];todo.pb(j);
l.pop(1,v.se,make_pair(v.fi,v.se));
r.pop(1,v.fi,make_pair(v.se,v.fi));
v=l.query(1,a[x]+1,b[x]-1);
}
v=r.query(1,a[x]+1,b[x]-1);
while(v.fi>b[x]){
// printf("%d %d\n",v.fi,v.se);
int j=id[make_pair(v.se,v.fi)];todo.pb(j);
l.pop(1,v.fi,make_pair(v.se,v.fi));
r.pop(1,v.se,make_pair(v.fi,v.se));
v=r.query(1,a[x]+1,b[x]-1);
}
foreach(it,todo) col[*it]=col[x]^1;
foreach(it,todo) dfs(*it);
}
struct segtree_minmax{
int op;
struct node{
int l,r,val;
} s[100005<<2];
inline void build(int k,int l,int r){
if(op==SEGTREE_MIN) s[k].val=0x3f3f3f3f;else s[k].val=0;
s[k].l=l;s[k].r=r;if(l==r) return;
int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline int query(int k,int l,int r){
if(l>r){
if(op==SEGTREE_MIN) return 0x3f3f3f3f;
else return 0;
}
if(l<=s[k].l&&s[k].r<=r) return s[k].val;
int mid=(s[k].l+s[k].r)>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else{
if(op==SEGTREE_MIN) return min(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
}
inline void modify(int k,int ind,int x){
if(s[k].l==s[k].r){
if(op==SEGTREE_MIN) s[k].val=min(s[k].val,x);
else s[k].val=max(s[k].val,x);
return;
}
int mid=(s[k].l+s[k].r)>>1;
if(ind<=mid) modify(k<<1,ind,x);
else modify(k<<1|1,ind,x);
if(op) s[k].val=min(s[k<<1].val,s[k<<1|1].val);
else s[k].val=max(s[k<<1].val,s[k<<1|1].val);
}
} L1,R1,L2,R2;
inline bool check(){
L1.op=SEGTREE_MIN;R1.op=SEGTREE_MAX;
L2.op=SEGTREE_MIN;R2.op=SEGTREE_MAX;
L1.build(1,1,n);R1.build(1,1,n);
L2.build(1,1,n);R2.build(1,1,n);
for(int i=1;i<=n;i++){
if(col[i]==1){
if(L1.query(1,a[i]+1,b[i]-1)<a[i]) return 0;
if(R1.query(1,a[i]+1,b[i]-1)>b[i]) return 0;
L1.modify(1,b[i],a[i]);R1.modify(1,a[i],b[i]);
}
else{
if(L2.query(1,a[i]+1,b[i]-1)<a[i]) return 0;
if(R2.query(1,a[i]+1,b[i]-1)>b[i]) return 0;
L2.modify(1,b[i],a[i]);R2.modify(1,a[i],b[i]);
}
}
return 1;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d",&a[i],&b[i]);
for(int i=1;i<=m;i++) id[make_pair(a[i],b[i])]=i;
l.op=SEGTREE_MIN;r.op=SEGTREE_MAX;l.build(1,1,n);r.build(1,1,n);
for(int i=1;i<=m;i++){
l.push(1,b[i],make_pair(a[i],b[i]));
r.push(1,a[i],make_pair(b[i],a[i]));
}
fill1(col);
for(int i=1;i<=m;i++){
if(!~col[i]){
col[i]=1;
l.pop(1,b[i],make_pair(a[i],b[i]));
r.pop(1,a[i],make_pair(b[i],a[i]));
dfs(i);
}
}
if(check())
for(int i=1;i<=m;i++) printf("%c\n",(col[i])?'S':'N');
else puts("IMPOSSIBLE");
return 0;
}
【2020五校联考NOIP #7】伟大的卫国战争的更多相关文章
- 【2020五校联考NOIP #6】三格缩进
题意: 给出 \(n\) 个数 \(a_1,a_2,\dots,a_n\),你要进行 \(m\) 次操作,每次操作有两种类型: \(1\ p\ x\):将 \(a_p\) 改为 \(x\). \(2\ ...
- 【2020五校联考NOIP #8】自闭
题目传送门 题意: 有一个 \(n \times m\) 的矩阵,里面已经填好了 \(k\) 个非负整数. 问是否能在其它 \(n \times m-k\) 个格子里各填上一个非负整数,使得得到的矩阵 ...
- 【2020五校联考NOIP #8】狗
题面传送门 原题题号:Codeforces 883D 题意: 有 \(n\) 个位置,每个位置上要么有一条狗,要么有一根骨头,要么啥都没有. 现在你要给每个狗指定一个方向(朝左或朝右). 朝左的狗可以 ...
- 【2020五校联考NOIP #7】道路扩建
题面传送门 题意: 给出一张 \(n\) 个点 \(m\) 条边的无向图 \(G\),第 \(i\) 条边连接 \(u_i,v_i\) 两个点,权值为 \(w_i\). 你可以进行以下操作一次: 选择 ...
- 【2020五校联考NOIP #4】今天的你依旧闪耀
题面传送门 题意: 对于一个长度为 \(n\)(\(n\) 为偶数)的排列 \(p\),定义一次"变换"后得到的排列 \(p'\) 为: \(p'_i=\begin{cases}p ...
- 【2020五校联考NOIP #3】序列
题面传送门 原题题号:Codeforces Gym 101821B 题意: 给出一个排列 \(p\),要你找出一个最长上升子序列(LIS)和一个最长下降子序列(LDS),满足它们没有公共元素.或告知无 ...
- 【2020五校联考NOIP #6】最佳观影
题意: 给出一个 \(k \times k\) 的网格和 \(n\) 次操作.其中 \(k\) 为奇数. 每次操作给出一个数 \(m\).每次你要找出一个三元组 \((x,l,r)\) 使得: \(r ...
- 【2020五校联考NOIP #2】矩阵
咕咕咕到现在~ 题面传送门 题意: 给出一个 \(n\times n\) 的矩阵 \(A\).要你求有多少个 \(n\times n\) 的矩阵 \(B\) 满足: 每一行都是 \(1\) 到 \(n ...
- 【五校联考1day2】JZOJ2020年8月12日提高组T2 我想大声告诉你
[五校联考1day2]JZOJ2020年8月12日提高组T2 我想大声告诉你 题目 Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...
随机推荐
- vue基础-组件&插槽
组件 组件化的意义:封装(复用,把逻辑隐藏起来,提高可维护性),快速开发(搭积木) 约定:我们通常把那些除了HTML标签以外的自定义组件,才称为'组件',结论是,我们说"父组件"& ...
- 【UE4 C++】打印字符串与输出日志
打印屏幕 默认打印屏幕 // 打印至屏幕 FString screenMessage = "(AddOnScreenDebugMessage) Hello world!"; GEn ...
- Windows平台编译器相关的几个预定义宏
WIN32 是在windows.h 中定义的宏,包含winodws.h则定义该宏 _WIN32/_WIN64跟windows平台有关的宏,_WIN32在windows 32位和64位下都有该宏,_ ...
- 鸿蒙轻内核M核的故障管家:Fault异常处理
摘要:本文先简单介绍下Fault异常类型,向量表及其代码,异常处理C语言程序,然后详细分析下异常处理汇编函数实现代码. 本文分享自华为云社区<鸿蒙轻内核M核源码分析系列十八 Fault异常处理& ...
- Git新建本地分支
作为一名码农,Git的使用就像家常便饭,时时刻刻都要用到. 通常我们在开发或者调试某个功能的时候,一般会从主分支新开一个单独的分支仅供自己使用,当我们开发完成后在提交合并请求给管理员,管理员进行代码审 ...
- fatal error: sqlite3.h: No such file or directory
编译带有sqlite3的数据库c语言程序时,出现fatal error: sqlite3.h: No such file or directory,找不到头文件的问题.应该是是系统没有安装函数库. 在 ...
- JAVA笔记9__异常/throw关键字/自定义异常/受检与非受检异常、assert关键字/StringBuffer、StringBuilder/代码国际化、动态文本
/** * 异常:在程序中导致程序中断运行的一些指令 * 1.受检异常:编译期 * 2.非受检异常:运行期 * 异常处理过程分析: * 1.一旦产生异常,系统会自动产生一个异常类的实例化对象 * 2. ...
- 使用.NET6打造动态API
ApiLite是直接将Service层自动生成api路由,可以不用添加Controller,支持模块插件化,在项目开发中能够提高工作效率,降低代码量. 开发环境 .NET SDK 6.0.100-rc ...
- VUE项目实现主题切换
需求是 做一个深色主题和浅色主题切换的效果 方法一 多套css 这个方法也是最简单,也是最无聊的. <!-- 中心 --> <template> 动态获取父级class名称,进 ...
- redis 的主从模式哨兵模式
原理理解 1,哨兵的作用就是检测redis主服务的状态,如果主服务器挂了,从服务就自动切换为主服务器,变为master.哨兵是一个独立的进程,作为进程,它会独立运行.其原理是哨兵通过发送命令,等待Re ...