Yet Another Range Query Problem

题解

首先,看到这道题,我们应该是比较容易联想到扫描线加线段树的。
我们考虑维护每个点作为左端点到当前扫到的这个点作为右端点之间区间的信息。
显然,我们每次多在末尾加入一个数,只会改变一段连续区间的最小值与一段连续区间的最大值。
这个显然可以用栈维护,找到它会改变的是哪一段,显然,如果一个数能覆盖上一个数,那他肯定是能覆盖上一个数覆盖的所有数的。所以这部分是O(n)O\left(n\right)O(n)的。

那我们考虑我们该怎么计算答案呢?
显然我们不大可能在每一层都询问一下包含这一层的所有询问,这不TTT麻才怪。
这也就是说我们必须通过差分求出我们的答案。
如果要差分的话也就是说我们得记录历史和,不过貌似这个历史和不太好通过懒标记进行区间更改,但它应该是可以的。
其实大部分这样的懒标记更改,最后统计和的,我们都可以考虑通过矩阵来实现。
我们假设每个点上就记录向量(∑min⁡,∑max⁡,∑min⁡⋅max⁡,history sum,size)(\sum \min,\sum \max,\sum \min \cdot \max,\text {history sum},size)(∑min,∑max,∑min⋅max,history sum,size)。
那么显然,我们的操作都可以表示成对这个向量乘上一个矩阵。
比如说我们更改最小值就会使得∑min⁡\sum\min∑min和∑min⁡⋅max⁡\sum \min\cdot\max∑min⋅max发生更改。
由于都是改成一个相同的值,也就是∑min⁡\sum\min∑min变成x⋅sizex\cdot sizex⋅size,∑min⁡⋅max⁡\sum \min\cdot\max∑min⋅max变成x∑max⁡x\sum\maxx∑max。
说成矩阵就是,
[0000001x000000000010x0001]\left[\begin{array}{cc} 0&0&0&0&0\\ 0&1&x&0&0\\ 0&0&0&0&0\\ 0&0&0&1&0\\ x&0&0&0&1 \end{array}\right ] ⎣⎢⎢⎢⎢⎡​0000x​01000​0x000​00010​00001​⎦⎥⎥⎥⎥⎤​
更改max⁡\maxmax的与之类似。
另外就是每一层都要将总和加到历史和上一次,就是一个单位矩阵在(3,4)(3,4)(3,4)上放个111即可。
询问的时候返回历史和那一维就行。

不过如果直接矩阵乘法的话可能会被卡常,可以只选择只会变动的那几位,事实上直接选择(1,3)(1,4)(2,3)(2,4)(5,1)(5,2)(5,3)(5,4)(1,3)(1,4)(2,3)(2,4)(5,1)(5,2)(5,3)(5,4)(1,3)(1,4)(2,3)(2,4)(5,1)(5,2)(5,3)(5,4)就行了,(1,1)(2,2)(3,3)(1,1)(2,2)(3,3)(1,1)(2,2)(3,3)都可以由其中的几个得出。
时间复杂度是大常数的O(nlog⁡n)O\left(n\log n\right)O(nlogn),嗯,毕竟我们没有矩乘。

源码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 150005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
typedef long double Ld;
typedef pair<LL,LL> pii;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int mod=1e6+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=200000;
const int n1=400;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-9;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
template<typename _T>
void print(_T x){if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,q,a[MAXN];
struct ming{int mn,mx,mul,siz,all;ming(){mn=mx=mul=siz=all=0;}
};
struct lazy{int admin,admax,admul,adall,mnmul,mxmul,mnall,mxall,mlall;lazy(){admin=admax=admul=adall=mnmul=mxmul=mnall=mxall=mlall=0;}
};
ming operator + (ming x,ming y){ming res;res.siz=x.siz+y.siz;res.mn=add(x.mn,y.mn,mo);res.mx=add(x.mx,y.mx,mo);res.mul=add(x.mul,y.mul,mo);res.all=add(x.all,y.all,mo);return res;
}
ming operator * (ming x,lazy y){ming res;res.siz=x.siz;res.all=x.all;if(y.admin)res.mn=1ll*x.siz*y.admin%mo;else res.mn=x.mn;if(y.admax)res.mx=1ll*x.siz*y.admax%mo;else res.mx=x.mx;if(y.admul||y.mnmul||y.mxmul)res.mul=(1ll*x.mn*y.mnmul+1ll*x.mx*y.mxmul+1ll*x.siz*y.admul)%mo;else res.mul=x.mul;Add(res.all,1ll*x.mul*y.mlall%mo,mo);Add(res.all,1ll*x.mx*y.mxall%mo,mo);Add(res.all,1ll*x.mn*y.mnall%mo,mo);Add(res.all,1ll*x.siz*y.adall%mo,mo);return res;
}
lazy operator * (lazy x,lazy y){lazy res;res.adall=add(x.adall,y.adall,mo);if(y.admin)res.admin=y.admin;else res.admin=x.admin;if(y.admax)res.admax=y.admax;else res.admax=x.admax;if(y.admul||y.mnmul||y.mxmul)res.admul=y.admul;else res.admul=x.admul;Add(res.adall,1ll*x.admin*y.mnall%mo,mo);Add(res.adall,1ll*x.admax*y.mxall%mo,mo);Add(res.adall,1ll*x.admul*y.mlall%mo,mo);res.mnall=(1ll*x.mnmul*y.mlall+x.mnall)%mo;if(!x.admin)Add(res.mnall,y.mnall,mo);res.mxall=(1ll*x.mxmul*y.mlall+x.mxall)%mo;if(!x.admax)Add(res.mxall,y.mxall,mo);Add(res.admul,1ll*x.admin*y.mnmul%mo,mo);Add(res.admul,1ll*x.admax*y.mxmul%mo,mo);res.mlall=x.mlall;if(!x.admul&&!x.mnmul&&!x.mxmul)Add(res.mlall,y.mlall,mo);if(!y.admul&&!y.mxmul&&!y.mnmul)Add(res.mxmul,x.mxmul,mo),Add(res.mnmul,x.mnmul,mo);if(!x.admax)Add(res.mxmul,y.mxmul,mo);if(!x.admin)Add(res.mnmul,y.mnmul,mo);return res;
}
class SegmentTree{private:ming tr[MAXN<<2];lazy lzy[MAXN<<2];void pushup(int rt){tr[rt]=tr[lson]+tr[rson];}void pushdown(int rt){if(lzy[rt].admin||lzy[rt].admax||lzy[rt].mlall){tr[lson]=tr[lson]*lzy[rt];lzy[lson]=lzy[lson]*lzy[rt];tr[rson]=tr[rson]*lzy[rt];lzy[rson]=lzy[rson]*lzy[rt];lzy[rt]=lazy();}}public:void build(int rt,int l,int r){tr[rt].siz=r-l+1;if(l==r)return ;int mid=l+r>>1;build(lson,l,mid);build(rson,mid+1,r);}void modifyMin(int rt,int l,int r,int al,int ar,int aw){if(l>r||l>ar||r<al||al>ar)return ;if(al<=l&&r<=ar){lazy tmp;tmp.admin=tmp.mxmul=aw;tr[rt]=tr[rt]*tmp;lzy[rt]=lzy[rt]*tmp;return ;}int mid=l+r>>1;pushdown(rt);if(al<=mid)modifyMin(lson,l,mid,al,ar,aw);if(ar>mid)modifyMin(rson,mid+1,r,al,ar,aw);pushup(rt);}void modifyMax(int rt,int l,int r,int al,int ar,int aw){if(l>r||l>ar||r<al||al>ar)return ;if(al<=l&&r<=ar){lazy tmp;tmp.admax=tmp.mnmul=aw;tr[rt]=tr[rt]*tmp;lzy[rt]=lzy[rt]*tmp;return ;}int mid=l+r>>1;pushdown(rt);if(al<=mid)modifyMax(lson,l,mid,al,ar,aw);if(ar>mid)modifyMax(rson,mid+1,r,al,ar,aw);pushup(rt);}void modify(int rt){lazy tmp;tmp.mlall=1;tr[rt]=tr[rt]*tmp;lzy[rt]=lzy[rt]*tmp;}int query(int rt,int l,int r,int al,int ar){if(l>r||l>ar||r<al||al>ar)return 0;if(al<=l&&r<=ar)return tr[rt].all;int mid=l+r>>1,res=0;pushdown(rt);if(al<=mid)Add(res,query(lson,l,mid,al,ar),mo);if(ar>mid)Add(res,query(rson,mid+1,r,al,ar),mo);return res;}
}T;
int stmin[MAXN],stmax[MAXN],stnk,stxk,ans[MAXN];
struct ask{int l,r,id,typ;};
vector<ask>vec[MAXN];
int main(){read(n);read(q);T.build(1,1,n);for(int i=1;i<=n;i++)read(a[i]);for(int i=1;i<=q;i++){int l,r,s,e;read(l);read(r);read(s);read(e);vec[e].pb((ask){l,r,i,1});vec[s-1].pb((ask){l,r,i,-1});}for(int i=1;i<=n;i++){while(stnk&&a[stmin[stnk]]>=a[i])stnk--;while(stxk&&a[stmax[stxk]]<=a[i])stxk--;T.modifyMin(1,1,n,stmin[stnk]+1,i,a[i]);stmin[++stnk]=i;T.modifyMax(1,1,n,stmax[stxk]+1,i,a[i]);stmax[++stxk]=i;T.modify(1);int siz=vec[i].size();for(int j=0;j<siz;j++)if(vec[i][j].typ>0)Add(ans[vec[i][j].id],T.query(1,1,n,vec[i][j].l,vec[i][j].r),mo);else Add(ans[vec[i][j].id],mo-T.query(1,1,n,vec[i][j].l,vec[i][j].r),mo);}for(int i=1;i<=q;i++)printf("%d\n",ans[i]);return 0;
}

谢谢!!!

[XXII Open Cup, Grand Prix of Korea M]Yet Another Range Query Problem相关推荐

  1. XXI Open Cup. Grand Prix of Korea I. Query On A Tree 17 树剖 + 二分 + 树带权重心

    传送门 文章目录 题意: 思路: 题意: 给你一棵树,每棵树初始权值都为000,现在给你两个操作: (1)(1)(1)将uuu的子树权值全部加111. (2)(2)(2)将(u,v)(u,v)(u,v ...

  2. G-Lexicographically Minimum Walk[CF-Gym-102391][2019-2020 XX Open Cup, Grand Prix of Korea]

    原题传送门 题面 Lexicographically Minimum Walk time limit per test2 secondsmemory limit per test1024 megaby ...

  3. [XXI Open Cup.Grand Prix of Korea]Advertisement Matching

    Advertisement Matching 题解 首先,题目的 a , b a,b a,b匹配显然是一个很常见的贪心. 有结论,设 a a a的集合为 A A A,如果 ∀ S ⊆ A , ∑ a ...

  4. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Korea

    A. Donut 扫描线+线段树. #include<cstdio> #include<algorithm> using namespace std; typedef long ...

  5. 2015-2016 XVI Open Cup, Grand Prix of Bashkortostan, SKB Kontur Cup Stage 2

    地址 Rank Solved A B C D E F G H I J K L M 72/213 8/13 O . O O . O . O O O . O Ø O: 当场通过 Ø: 赛后通过 .: 尚未 ...

  6. 2020-2021 Winter Petrozavodsk Camp, Belarusian SU Contest (XXI Open Cup, Grand Prix of Belarus)

    题目链接 C. Brave Seekers of Unicorns 给出一个好数组的定义: 1.1.1. 长度不为空 2.2.2. a[i]⨁a[i−1]⨁a[i−2]≠0a[i] \bigoplus ...

  7. 2020-2021 ACM-ICPC, Asia Nanjing Regional Contest (XXI Open Cup, Grand Prix of Nanjing)

    M. Monster Hunter 树形背包dp dp[i][j][k] 表示结点i的子树中有j个节点存活且当前节点i的状态为(0/1) 转移方程: dp[x][i+j][0]=min(dp[x][i ...

  8. [XXI Open Cup,Grand Prix of Tokyo]Ascending Matrix

    Ascending Matrix 题解 首先,这道题是要求所有的数列是从上往下,从左往右,都是递增的. 首先从左往右递增,我们可以去考虑它的差分序列,每个点的值就是它前面差分序列的点数嘛. 从上往下递 ...

  9. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of SPb

    A. Base $i - 1$ Notation 两个性质: $2=1100$ $122=0$ 利用这两条性质实现高精度加法即可. 时间复杂度$O(n)$. #include<stdio.h&g ...

最新文章

  1. python中噪音是什么意思_Python数据噪音
  2. 并发编程6 锁进程队列
  3. Windows和Linux双系统时间不对的问题。
  4. xml解析:Sax,Dom,pull解析
  5. 轻量级Web应用程序:PrimeFaces(JSF)+ Guice + MyBatis(第1部分)
  6. 你不知道的JavaScript-0
  7. typescript 学习
  8. Juniper Olive动态路由RIP配置案例
  9. c语言结果输出10遍,C语言 如何实现输出这样一系列输出结果
  10. python中 tolist_python 列表,数组,矩阵两两转换tolist()的实例
  11. 太阳升起并下落的小动画-SWIFT
  12. XP远程桌面连接网络无法验证解决办法
  13. 百战程序员python视频下载_[视频教程] 百战程序员python400集(第一季115集)
  14. 必须重启计算机才能关闭用户账户控制,Win10系统怎么彻底关闭用户帐户控制?...
  15. 为什么AI公司都在一边融资,一边投资? | 甲子光年
  16. Win11系统显示和隐藏语言栏的操作方法分享
  17. 老年人微信教程手绘版|微信入门教程1
  18. 【蓝桥杯】特别数的和
  19. 解读公司搬家注意事项
  20. office 文档 在线查看

热门文章

  1. 用 NetworkX + Gephi + Nebula Graph 分析<权力的游戏>人物关系(下篇)
  2. 遇到黑客攻击遭遇勒索保护费怎么办?黑客最常见的攻击手段
  3. 解决Navicat1166错误
  4. 【CMake 语法】(6) CMake 条件、循环、跳出循环
  5. python大写数字转阿拉伯数字脚本
  6. fMRI脑影像特征提取——Pearson相关与低阶功能连接LOFC(dpabi+nilearn)
  7. 可怕!一部手机失窃而揭露的黑色产业链
  8. cuteftp连接ubuntu虚拟机
  9. python灰色波浪线_PyCharm取消波浪线、下划线和中划线的实现
  10. “云计算机”是什么?