Mokia CDQ分治+容斥
Mokia CDQ分治+容斥
题目描述#
维护一个的矩阵,初始值均为.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数,询问数.
输入格式#
第一行两个整数;其中为矩阵初始值;为矩阵大小
接下来每行为一下三种输入之一(不包含引号):
输入:你需要把(第行第列)的格子权值增加
输入:你需要求出以左下角为,右上角为的矩阵内所有格子的权值和,并输出
输入:表示输入结束
输出格式#
对于每个输入,输出一行,即输入的答案
样例#
样例输入#
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
样例输出#
3
5
数据范围与提示
保证答案不会超过范围
分析#
我们会发现格子很大,但是修改数和查询数比较小
因此,我们肯定不能维护整个格子,而要从修改和查询上找突破口
我们设第次修改的点的横纵坐标分别为 ,如果它要对之后的某个矩形产生贡献的话
必须满足
如果加上时间的限制,那么就是一个五维的偏序,不好处理
我们可以用容斥的方法把一个大矩形分成四个小矩形,类似于求前缀和的方法
即
表示原点和 围成的矩形所增加的值
这样问题就变成了一个三维偏序
然后就可以离线用 分治解决
代码#
复制#include<cstdio>
#include<algorithm>
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=2e6+5;
struct asd{
int id,x,y,wz,val;
bool jud;
asd(){}
asd(int aa,int bb,int cc,int dd,int ee,bool ff){
id=aa,x=bb,y=cc,wz=dd,val=ee,jud=ff;
}
}b[maxn];
int s,w,cnt,js;
bool cmp1(asd aa,asd bb){
if(aa.id==bb.id && aa.x==bb.x) return aa.y<bb.y;
if(aa.id==bb.id) return aa.x<bb.x;
return aa.id<bb.id;
}
bool cmp2(asd aa,asd bb){
if(aa.x==bb.x) return aa.y<bb.y;
return aa.x<bb.x;
}
int lb(int xx){
return xx&-xx;
}
int tr[maxn];
void ad(int wz,int val){
for(int i=wz;i<maxn;i+=lb(i)){
tr[i]+=val;
}
}
int cx(int wz){
int nans=0;
for(int i=wz;i>0;i-=lb(i)){
nans+=tr[i];
}
return nans;
}
int ans[maxn][6];
void solve(int l,int r){
if(l==r) return;
int mids=(l+r)>>1;
solve(l,mids);
solve(mids+1,r);
std::sort(b+l,b+mids+1,cmp2);
std::sort(b+mids+1,b+r+1,cmp2);
int now=l;
for(int i=mids+1;i<=r;i++){
while(now<=mids && b[now].x<=b[i].x){
if(!b[now].jud){
ad(b[now].y,b[now].val);
}
now++;
}
if(b[i].jud){
ans[b[i].id][b[i].wz]+=cx(b[i].y);
}
}
for(int i=now-1;i>=l;i--){
if(!b[i].jud){
ad(b[i].y,-b[i].val);
}
}
}
int jl[maxn],anss[maxn];
int main(){
s=read(),w=read();
while(1){
int aa,bb,cc,dd,ee;
aa=read();
js++;
jl[js]=aa;
if(aa==1){
bb=read(),cc=read(),dd=read();
bb++,cc++;
b[++cnt]=asd(js,bb,cc,0,dd,0);
} else if(aa==2){
bb=read(),cc=read(),dd=read(),ee=read();
bb++,cc++,dd++,ee++;
b[++cnt]=asd(js,dd,ee,1,0,1);
b[++cnt]=asd(js,dd,cc-1,2,0,1);
b[++cnt]=asd(js,bb-1,ee,3,0,1);
b[++cnt]=asd(js,bb-1,cc-1,4,0,1);
anss[js]=(dd-bb+1)*(ee-cc+1)*s;
} else {
break;
}
}
std::sort(b+1,b+1+cnt,cmp1);
solve(1,cnt);
for(int i=1;i<js;i++){
if(jl[i]==2){
printf("%d\n",ans[i][1]-ans[i][2]-ans[i][3]+ans[i][4]+anss[i]);
}
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)