LOJ

洛谷


先令编号从\(1\)开始。我们要求\([1,i]\)这些数字能否构成一个矩形。

考虑能否用线段树维护,让每个叶子节点\(i\)表示前\(i\)个数能否构成矩形。

一种方法是维护前\(i\)个点最左上点和最右下点的坐标,直接判断这两个点构成的矩形面积是否是\(i\)。

发现修改的时候这个最值不好维护,每次修改可能是\(O(n)\)的。

考虑合法矩形的特征。把前\(i\)个点标记为黑点,其余点是白点。那么前\(i\)个点构成了一个矩形当且仅当:

  1. 左边和上边都是白点的黑点有且只有一个。
  2. 不存在一个白点,它的上下左右有两个及以上黑点。

正确性比较显然...?(雾)不说了。

记左边上边都是白点的黑点数量为\(t1\),上下左右有两个及以上黑点是白点数量为\(t2\)。注意到\(t1>0\),\(t2\)非负,那么\(i\)合法当且仅当\(t1+t2=1\),所以只在叶节点处维护前\(i\)个点为黑点时,\(t1+t2\)的值就好了。非叶节点就维护区间最小值及最小值的个数。

考虑修改时如何维护。

记\(l\)为点\(i\)周围点(上下左右)编号的次小值,点\(i\)作为白点时,会对\([l,i-1]\)这些位置有贡献。

记\(r\)为点\(i\)左边、上边的点的编号的最小值,那么点\(i\)作为黑点时,会对\([i,r-1]\)这些位置有贡献。

每次交换两个点\(x,y\),最多只会影响\(10\)个点的\(l,r\),所以把这些点取出来,减掉在线段树上的贡献,交换\(x,y\)之后再把它们的贡献加上即可。

注意要对这些点判重。


//27496ms	1688K
#include "seats.h"
#include <cstdio>
#include <cctype>
#include <algorithm>
#define F(p,i) (p+Way[i])
#define ID(x,y) ((x-1)*m+y)
#define Check(x,y) (x>=1&&x<=n&&y>=1&&y<=m)
#define gc() getchar()
const int N=1e6+5,Way[]={1,0,-1,0,1};//down left up right int n,m,tot,A[N],X[N],Y[N],val[N];
struct Segment_Tree
{
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,ls
#define rson m+1,r,rs
#define S N<<2
int mn[S],cnt[S],tag[S];
#undef S
#define Upd(rt,v) tag[rt]+=v, mn[rt]+=v
#define Update(rt) mn[rt]=std::min(mn[ls],mn[rs]), cnt[rt]=(mn[rt]==mn[ls]?cnt[ls]:0)+(mn[rt]==mn[rs]?cnt[rs]:0)
inline void PushDown(int rt)
{
Upd(ls,tag[rt]), Upd(rs,tag[rt]), tag[rt]=0;
}
void Build(int l,int r,int rt)
{
if(l==r)
{
mn[rt]=val[l], cnt[rt]=1;
return;
}
int m=l+r>>1;
Build(lson), Build(rson), Update(rt);
}
void Modify(int l,int r,int rt,int L,int R,int v)
{
if(L<=l && r<=R) {Upd(rt,v); return;}
if(tag[rt]) PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify(lson,L,R,v);
if(m<R) Modify(rson,L,R,v);
Update(rt);
}
}T; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline int CalcW(int p)
{
int mn1=tot+1,mn2=mn1,x=X[p],y=Y[p];
for(int i=0,xn,yn; i<4; ++i)
if(xn=F(x,i),yn=F(y,i+1),Check(xn,yn))
{
int w=A[ID(xn,yn)];
if(w<mn1) mn2=mn1, mn1=w;
else if(w<mn2) mn2=w;
}
return mn2;
}
inline int CalcB(int p)
{
int x=X[p],y=Y[p],xn1=F(x,1),yn1=F(y,2),xn2=F(x,2),yn2=F(y,3);
return std::min(Check(xn1,yn1)?A[ID(xn1,yn1)]:tot+1,Check(xn2,yn2)?A[ID(xn2,yn2)]:tot+1);
}
#define S 1,tot,1
void give_initial_chart(int n,int m,std::vector<int> R,std::vector<int> C)
{
int tot=n*m; ::n=n, ::m=m, ::tot=tot;
for(int i=1; i<=tot; ++i) X[i]=R[i-1]+1,Y[i]=C[i-1]+1,A[ID(X[i],Y[i])]=i;
// for(int i=1; i<=tot; ++i) X[i]=read()+1,Y[i]=read()+1,A[ID(X[i],Y[i])]=i;
for(int i=1; i<=tot; ++i)
{
val[i]=val[i-1];
if(CalcW(i)<i) --val[i];
if(CalcB(i)>i) ++val[i];
for(int j=0,x=X[i],y=Y[i],xn,yn,w; j<4; ++j)
if(xn=F(x,j),yn=F(y,j+1),Check(xn,yn))
{
if((w=A[ID(xn,yn)])<i && CalcB(w)==i) --val[i];
else if(w>i && CalcW(w)==i) ++val[i];
}
}
T.Build(S);
}
int swap_seats(int a,int b)
{
static int B[12];
++a, ++b;
int x=X[a],y=Y[a],t=2; B[1]=a, B[2]=b;
for(int i=0,xn,yn; i<4; ++i)
if(xn=F(x,i),yn=F(y,i+1),Check(xn,yn)) B[++t]=A[ID(xn,yn)];
x=X[b],y=Y[b];
for(int i=0,xn,yn; i<4; ++i)
if(xn=F(x,i),yn=F(y,i+1),Check(xn,yn)) B[++t]=A[ID(xn,yn)];
std::sort(B+1,B+1+t);
for(int i=1; i<=t; ++i)
if(B[i]!=B[i-1])
{
int p=B[i],l=CalcW(p),r=CalcB(p);
if(l<p) T.Modify(S,l,p-1,-1);
if(r>p) T.Modify(S,p,r-1,-1);
}
std::swap(A[ID(X[a],Y[a])],A[ID(X[b],Y[b])]);
std::swap(X[a],X[b]), std::swap(Y[a],Y[b]);
for(int i=1; i<=t; ++i)
if(B[i]!=B[i-1])
{
int p=B[i],l=CalcW(p),r=CalcB(p);
if(l<p) T.Modify(S,l,p-1,1);
if(r>p) T.Modify(S,p,r-1,1);
}
return T.cnt[1];
} //int main()
//{
// int n=read(),m=read(),Q=read(); ::n=n, ::m=m;
// give_initial_chart(n,m);
// while(Q--) printf("%d\n",swap_seats(read(),read()));
//
// return 0;
//}

LOJ.2864.[IOI2018]排座位(线段树)的更多相关文章

  1. [IOI2018]排座位——线段树

    题目链接: IOI2018seat 题目大意:给出一个$H*W$的矩阵,将$0 \sim W*H-1$分别填入矩阵的格子里(每个格子里一个数),定义一个子矩阵是美妙的当且仅当这个子矩阵包含且仅包含$0 ...

  2. 【LOJ#6029】市场(线段树)

    [LOJ#6029]市场(线段树) 题面 LOJ 题解 看着就是一个需要势能分析的线段树. 不难发现就是把第二个整除操作化为减法. 考虑一下什么时候整除操作才能变成减法. 假设两个数为\(a,b\). ...

  3. 【Loj#535】花火(线段树,扫描线)

    [Loj#535]花火(线段树,扫描线) 题面 Loj 题解 首先如果不考虑交换任意两个数这个操作,答案就是逆序对的个数. 那么暴力就是枚举交换哪个两个数,然后用数据结构之类的东西动态维护逆序对. 但 ...

  4. Loj #2570. 「ZJOI2017」线段树

    Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...

  5. LOJ#3043.【ZJOI2019】 线段树 线段树,概率期望

    原文链接www.cnblogs.com/zhouzhendong/p/ZJOI2019Day1T2.html 前言 在LOJ交了一下我的代码,发现它比选手机快将近 4 倍. 题解 对于线段树上每一个节 ...

  6. [IOI2018]会议——分治+线段树

    题目链接: [IOI2018]meetings 题目大意:有$n$座山峰,每座山峰有一个高度,有$q$次询问,每次需要确定一个开会山峰使$[l,r]$所有山峰上的人都前往开会山峰,一个山峰的人去开会的 ...

  7. [loj#2005][SDOI2017]相关分析 _线段树

    「SDOI2017」相关分析 题目链接:https://loj.ac/problem/2005 题解: 把上面的式子拆掉,把下面的式子拆掉. 发现所有的东西都能用线段树暴力维护. 代码: #inclu ...

  8. [IOI2018]机械娃娃——线段树+构造

    题目链接: IOI2018doll 题目大意:有一个起点和$m$个触发器,给出一个长度为$n$的序列$a$,要求从起点出发按$a$的顺序经过触发器并回到起点(一个触发器可能被经过多次也可能不被经过), ...

  9. [LOJ#2980][THUSCH2017]大魔法师(线段树+矩阵)

    每个线段树维护一个行向量[A,B,C,len]分别是这个区间的A,B,C区间和与区间长度,转移显然. 以及此题卡常,稍微哪里写丑了就能100->45. #include<cstdio> ...

随机推荐

  1. 洛谷P1108 低价购买题解

    看到"你必须用低于你上次购买它的价格购买它",有没有想到什么?没错,又是LIS,倒过来的LIS,所以我们只要把读入的序列倒过来就可以求LIS了,第一问解决. 首先要厘清的是,对于这 ...

  2. 解决远程连接MongoDB出现错误

    前言:最近准备学习下MongoDB,安装什么的都已经弄完了,想远程连接来管理MongoDB,用的软件是robo 3t 第一次连的时候就出错误了 大概意思是连接失败,解决如下 第一步,首先检查你的服务器 ...

  3. [jzoj]4271. 【NOIP2015模拟10.27】魔法阵(37种转移的dp)

    题意不说 应该这辈子都不会忘记了... 这是我人生中做的最SB的一道DP题. 真的打的我心态崩了.... 可是竟然被我调出来了..... 也是没谁了... 我们设\(F[i][j][S]\)表示到第\ ...

  4. JS学习笔记Day12

    一.浏览器的默认行为以及阻止行为 (一)右键菜单事件:oncontextmenu: 阻止:return false: (二)超链接的默认行为:跳转: 阻止:标准浏览器:event.preventDef ...

  5. Python变量命名规范

    模块名: 小写字母,单词之间用_分割 ad_stats.py 包名: 和模块名一样 类名: 单词首字母大写 AdStats ConfigUtil 全局变量名(类变量,在java中相当于static变量 ...

  6. 金融量化分析【day112】:量化平台的使用-初始化函数

    一.set_benchmark - 设置基准 1.实现代码 # 导入函数库 import jqdata #初始化函数,设定基准等等 def initialize(context): set_bench ...

  7. 闭包创建自己的 plugin 示例 加载 loading

    plugin  插件 什么是 plugin? 实现一个功能,与主应用程序分离,减少主应用程序的大小,高复用,可维护 制作过程中,一定要避免依赖其他的元素,减少 id 等的使用,避免与页面中其他内容冲突 ...

  8. [再寄小读者之数学篇](2014-04-18 from 352558840@qq.com [南开大学 2014 年高等代数考研试题]反对称矩阵的组合)

    (2014-04-18 from 352558840@qq.com [南开大学 2014 年高等代数考研试题]反对称矩阵的组合) 设 ${\bf A},{\bf B}$ 都是反对称矩阵, 且 ${\b ...

  9. unix域字节流回射程序

    一.服务端程序 #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <uni ...

  10. Contest2161 - 2019-3-21 高一noip基础知识点 测试4 题解版

    传送门 预计得分:100+100+100+10=310 实际得分:100+0+82+10=192 你们基础知识不行啊——by wxg T1 一看数据范围就是搜索 但是不能因为数据范围就断送了dp的心 ...