CF1093E 题解
来一发 \(O(n \sqrt n)\) 时间,\(O(n)\) 空间的分块写法。
首先建模,把 数值 \(x\) 在两个数组中出现的位置作为坐标,问题就转化为一个二维动态数点。
考虑用序列分块维护第一维,第二维用 值域分块 维护,这样子平衡复杂度玩就得到一个 \(O(n \sqrt n)\) 时间的做法,但是空间很大。
考虑到块与块之间并无联系,所以考虑 逐块处理 也就是说把每个块的修改与贡献离线下来分开计算,那么空间就被优化到了 \(O(n)\)。
综上,我们就可以写出代码了。
#include<bits/stdc++.h>
#define int long long
//#define lowbit(x) (x&-(x))
using namespace std;
const int maxn = 6e5+114;
const int maxsq = 500;
const int warma = 447;
int n,cnt;
struct Node{
int opt,x,l,r,L,R;
}Q[maxn];
int anser[maxn];
pair<int,int> wyb[maxn],zbz[maxn];//处理时的数组 & 原本的数组
int val(int l1,int r1,int l2,int r2){//计算两个区间的交集大小
int mxl=max(l1,l2),mir=min(r1,r2);
if(mxl>mir) return 0;
else return (mir-mxl+1);
}
class block{//O(\sqrt n) 区间修改 O(1) 区间查询
private:
int bl_pre[maxsq][maxsq];//块内前缀和
int tag[maxsq];//块内标记
int pre[maxsq];//块间前缀和
public:
void add(int l,int r,int v);
int query(int l,int r);
void init();
}chifan;
void block::init(){
for(int i=0;i<maxsq;i++)
for(int j=0;j<maxsq;j++)
bl_pre[i][j]=tag[i]=pre[i]=0;
}
void block::add(int l,int r,int v){
int bl=l/warma;
int lpos=l%warma;
if(lpos==0){
lpos=warma;
bl--;
}
int br=r/warma;
int rpos=r%warma;
if(rpos==0){
rpos=warma;
br--;
}
//整块处理
if(bl==br){
for(int i=lpos;i<=rpos;i++){
bl_pre[bl][i]+=v*(i-lpos+1);
}
for(int i=rpos+1;i<=warma;i++){
bl_pre[bl][i]+=v*(rpos-lpos+1);
}
pre[0]=bl_pre[0][warma];
for(int i=1;i<=warma;i++){
pre[i]=pre[i-1]+bl_pre[i][warma]+tag[i]*warma;
}
return ;
}
for(int i=bl+1;i<=br-1;i++){
tag[i]+=v;
}
//头部残块处理
for(int i=lpos;i<=warma;i++){
bl_pre[bl][i]+=v*(i-lpos+1);
}
//尾部残块处理
for(int i=1;i<=rpos;i++){
bl_pre[br][i]+=v*i;
}
for(int i=rpos+1;i<=warma;i++){
bl_pre[br][i]+=v*rpos;
}
//块间处理
pre[0]=bl_pre[0][warma];
for(int i=1;i<=warma;i++){
pre[i]=pre[i-1]+bl_pre[i][warma]+tag[i]*warma;
}
return ;
}
int block::query(int l,int r){
int bl=l/warma;
int lpos=l%warma;
if(lpos==0){
lpos=warma;
bl--;
}
int br=r/warma;
int rpos=r%warma;
if(rpos==0){
rpos=warma;
br--;
}
if(bl==br){
return bl_pre[bl][rpos]-bl_pre[bl][lpos-1]+tag[bl]*(rpos-lpos+1);
}
int res=0;
res+=pre[br-1]-pre[bl];
res+=bl_pre[bl][warma]-bl_pre[bl][lpos-1]+(warma-lpos+1)*tag[bl];
res+=bl_pre[br][rpos]+tag[br]*rpos;
return res;
}
void work(int lt,int rt){//逐块处理
rt=min(rt,n);
chifan.init();
for(int i=1;i<=n;i++) wyb[i]=zbz[i];
for(int i=lt;i<=rt;i++){
chifan.add(wyb[i].first,wyb[i].second,1);
}
for(int i=1;i<=cnt;i++){
if(Q[i].opt==1){
int l=Q[i].l,r=Q[i].r,L=Q[i].L,R=Q[i].R;
if(l<=lt&&rt<=r){//被包含
anser[i]+=chifan.query(L,R);
}
else if(lt<=l&&r<=rt){//另外一种被包含
int res=0;
for(int i=l;i<=r;i++){
res+=val(wyb[i].first,wyb[i].second,L,R);
}
anser[i]+=res;
}
else if(rt>=r&&r>=lt){
int res=0;
for(int i=lt;i<=r;i++){
res+=val(wyb[i].first,wyb[i].second,L,R);
}
anser[i]+=res;
}
else if(lt<=l&&l<=rt){
int res=0;
for(int i=l;i<=rt;i++){
res+=val(wyb[i].first,wyb[i].second,L,R);
}
anser[i]+=res;
}
}
else{
int x=Q[i].x,l=Q[i].l,r=Q[i].r;
if(lt<=x&&x<=rt){
chifan.add(wyb[x].first,wyb[x].second,-1);
wyb[x].first=l,wyb[x].second=r;
chifan.add(wyb[x].first,wyb[x].second,1);
}
}
}
}
int sq;
int q;
int a[maxn],b[maxn];
int A[maxn],B[maxn];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
sq=sqrt(n);
for(int i=1;i<=n;i++){
cin>>a[i];
A[a[i]]=i;
}
for(int i=1;i<=n;i++){
cin>>b[i];
B[b[i]]=i;
}
for(int i=1;i<=n;i++){
zbz[A[i]].first=B[i];
zbz[A[i]].second=B[i];
}
for(int i=1;i<=q;i++){
int OPT;
cin>>OPT;
if(OPT==1){
int la,ra,lb,rb;
cin>>la>>ra>>lb>>rb;
cnt++;
Q[cnt].opt=1;
Q[cnt].l=la;
Q[cnt].r=ra;
Q[cnt].L=lb;
Q[cnt].R=rb;
}
else{
int x,y;
cin>>x>>y;
//b[x] - A[b[x]] x -> A[b[x]] y
//b[y] - A[b[y]] y -> A[b[y]] x
//b[x] - b[y]
//B[b[x]]
cnt++;
Q[cnt].opt=2;
Q[cnt].x=A[b[x]];
Q[cnt].l=y;
Q[cnt].r=y;
cnt++;
Q[cnt].opt=2;
Q[cnt].x=A[b[y]];
Q[cnt].l=x;
Q[cnt].r=x;
swap(b[x],b[y]);
swap(B[b[x]],B[b[y]]);
}
}
int L=1,R=sq;
while(L<=n){
work(L,R);
L+=sq,R+=sq;
}
for(int i=1;i<=cnt;i++){
if(Q[i].opt==1) cout<<anser[i]<<'\n';
}
}
/*
6 2
5 1 4 2 3 6
2 5 3 1 4 6
2 2 4
1 2 3 3 5
*/
题外话:这一道题我口胡过一个线段加和一个二维数最大值的加强版(而且写出来了,这题代码就是这么改出来的)。
CF1093E 题解的更多相关文章
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
- JSOI2016R3 瞎BB题解
题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...
随机推荐
- Java中的多态、抽象类和接口简述
1. 引言 本文对Java编程中的多态.抽象类和接口概念进行了简明扼要的讲解,并对extends和implements进行了辨析. 2. 多态 多态是指所调用的方法只有在运行的时候才可以明确,如下例所 ...
- golang中三种定时器的实现方式及周期定时
一.定时器的创建 golang中定时器有三种实现方式,分别是time.sleep.time.after.time.Timer 其中time.after和time.Timer需要对通道进行释放才能达到定 ...
- Gin框架
目录 gin的参数获取 header参数 post Raw json 请求示例 gin的参数获取 package main import ( "fmt" "github. ...
- iceoryx源码阅读(六)——共享内存创建
目录 1 共享内存的组织 2 共享内存创建 2.1 IceOryxRouDiMemoryManager::createAndAnnounceMemory 2.2 RouDiMemoryManager: ...
- 09. C语言内嵌汇编代码
C语言函数内可以自定义一段汇编代码,在GCC编译器中使用 asm 或 __asm__ 关键词定义一段汇编代码,并可选添加volatile关键字,表示不要让编译器优化这段汇编代码. 内嵌汇编代码格式如下 ...
- 逆向wechat
本篇博客园地址https://www.cnblogs.com/bbqzsl/p/18171552 计划来个wechat的逆向系列,包括主程序WeChat,以及小程序RadiumWMPF. 开篇,对We ...
- kubernetes 之dashboard
部署 kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recomme ...
- Java手机号校验规则最新
一.最新的Java手机号校验规则 在Java中,进行手机号校验通常使用正则表达式(Regex)来匹配手机号的格式.以下是一个基于当前(截至2024年)中国手机号规则的校验方法: 中国手机号通常以数字1 ...
- Canny边缘检测实现(Opencv C++)
Canny边缘检测是Canny在1986年提出来的,目前仍是图像边缘检测算法中最经典.先进的算法之一.canny方法基于如下三个基本目标: 1. 低错误率:所有边缘都应被找到,并且不应有虚假响应. 2 ...
- ETL工具-nifi干货系列 第五讲 处理器GenerateFlowFile
1.今天我们一起来学习处理器GenerateFlowFile.这个处理器创建带有随机数据或自定义内容的 FlowFiles.GenerateFlowFile 对于负载测试.配置和模拟非常有用.从工具栏 ...