您的位置:首页 > 其它

BZOJ 1176 Mokia(CDQ分治)

2018-03-30 17:09 344 查看
题目链接:BZOJ 1176

题目大意:维护一个W*W的矩阵,初始值均为S。每次操作可以增加某格子的权值或询问某子矩阵的总权值(修改操作数M<=160000,询问数Q<=10000,W<=2000000)。

题解:CDQ分治。查询操作可以分成4个(1,1)到(x,y)的子矩形的权值和查询,再加加减减。先把操作按x坐标为第一关键字,y为第二关键字排序,然后按操作的先后分治。分治的每一层里,计算左边的修改对右边的查询造成的影响,由于保证了右边询问的x坐标不小于左边修改的x坐标,用一个下标为y坐标的树状数组统计就好了,然后分治下去。

code(没有权限,并不保证AC TAT)


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 2000005
#define maxm 640005
#define maxq 10005
#define lowbit(x) ((x)&(-x))
inline int read()
{
char c=getchar(); int num=0,f=1;
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); }
return num*f;
}
int n,bit[maxn],ans[maxq];
struct data{
int opt,id,qid,x,y,c;
data(int _opt=0,int _id=0,int _qid=0,int _x=0,int _y=0,int _c=0)
{
opt=_opt; id=_id; qid=_qid;
x=_x; y=_y; c=_c;
}
}c[maxm],tmp[maxm];
inline void add(int pos,int val)
{
for (;pos<=n;pos+=lowbit(pos)) bit[pos]+=val;
}
inline int sum(int pos)
{
int ret=0;
for (;pos;pos-=lowbit(pos)) ret+=bit[pos];
return ret;
}
inline int cmp(data a,data b)
{
return (a.x!=b.x)?(a.x<b.x):((a.y!=b.y)?(a.y<b.y):(a.opt<b.opt));
}
void cdq(int l,int r)
{
if (l==r) return;
int mid=l+r>>1;
for (int i=l;i<=r;i++)
{
if (c[i].opt==1&&c[i].id<=mid)
add(c[i].y,c[i].c);
else if (c[i].opt==2&&c[i].id>mid)
ans[c[i].qid]+=c[i].c*sum(c[i].y);
}
for (int i=l;i<=r;i++) //清空树状数组,即保证了每次只统计当前区间前一半修改对后一半询问的影响
if (c[i].opt==1&&c[i].id<=mid) add(c[i].y,-c[i].c);
int h1=l,h2=mid;
for (int i=l;i<=r;i++)   // 保证分治到每一层时所有操作是x坐标有序的
if (c[i].id<=mid) tmp[h1++]=c[i];
else tmp[++h2]=c[i];
for (int i=l;i<=r;i++) c[i]=tmp[i];
cdq(l,mid); cdq(mid+1,r);
}
int main()
{
int s=read(),n=read(),tot=0,id=0;
while (true)
{
int opt=read();
if (opt==3) break;
if (opt==1)
{
int x=read(),y=read(),w=read();
tot++; data oh(1,tot,0,x,y,w);
c[tot]=oh;
}
else
{
int x1=read(),y1=read(),x2=read(),y2=read(); id++;
tot++; data d1(2,tot,id,x2,y2,1);
c[tot]=d1;
tot++; data d2(2,tot,id,x1-1,y2,-1);
c[tot]=d2;
tot++; data d3(2,tot,id,x2,y1-1,-1);
c[tot]=d3;
tot++; data d4(2,tot,id,x1-1,y1-1,1);
c[tot]=d4;
ans[id]=(y2-y1+1)*(x2-x1+1)*s;
}
}
sort(c+1,c+tot+1,cmp);
cdq(1,tot);
for (int i=1;i<=id;i++) printf("%d\n",ans[i]);
return 0;
}


总结:感觉做CDQ分治的题要考虑好左边对右边的影响怎么统计、每一层需不需要清空、需不需要保证有序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: