人生第一道自己写的CDQ LOL~~~
题目大意
维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
题解
CDQ分治裸上啊...
啥是CDQ啊?....
怎么说呢..
CDQ分治是一种思想.
将整个序列分成两半递归处理,但是由于左边对右边的序列存在着不可忽略的影响,所以需要在递归时考虑左半边序列对右半边序列的影响。
即CDQ的核心思想.(大概...)
至于具体的实现过程,这种东西还是对着代码比较好学。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxm = 210010;
const int maxn = 2100000;
struct Node{
int op,x,y;
int val,id;
bool friend operator < (const Node &a,const Node &b){
return a.x < b.x;
}Node(){}
Node(int a,int b,int c,int d,int e){op=a;x=b;y=c;val=d;id = e;}
}a[maxm],atmp[maxm];
int cnt,n;
int anss[10010];
int c[maxn],tmp[maxm];
#define lowbit(x) (x&-x)
inline void modify(int x,int y){
if(!x) return;
for(;x <= n;x+=lowbit(x)) c[x] += y;
}
inline int query(int x){
int ret = 0;
for(;x>=1;x-=lowbit(x)) ret += c[x];
return ret;
}
inline void merge(int l,int r){
if(l == r) return;
int mid = l+r >> 1;
int i = l,j = mid+1,k = l;
while(i <= mid || j <= r){
if(j > r || ( i <= mid && a[i].x < a[j].x)) atmp[k++] = a[i++];
else atmp[k++] = a[j++];
}for(int i=l;i<=r;++i) a[i] = atmp[i];
}
void solve(int l,int r){//CDQ的分治
if(l == r) return ;
int mid = l+r >> 1;
solve(l,mid);//递归处理子序列
solve(mid+1,r);
merge(l,mid);//对左右序列分别排序
merge(mid+1,r);
//下面开始考虑左序列(中的插入操作)对右序列(中的询问操作)的影响
int p = l,cnt = 0;
for(int i = mid+1;i<=r;++i){
if(a[i].op == 2){//如果这是个询问操作
while(p <= mid && a[p].x <= a[i].x){
if(a[p].op == 1){//对于左序列所有的操作,更新影响
tmp[++cnt] = p;
modify(a[p].y,a[p].val);
}++p;
}anss[a[i].id] += a[i].val*query(a[i].y);//做出贡献
}
}
//清空树状数组,注意不能memset
for(int i=1;i<=cnt;++i) modify(a[tmp[i]].y,-a[tmp[i]].val);
}
int main(){
read(cnt);read(n);
int op,x1,y1,x2,y2,x;
int query_id = 0;
while(1){
read(op);if(op == 3) break;
if(op == 1){
read(x1);read(y1);read(x);
a[++cnt] = (Node){op,x1,y1,x,0};
}else{
x = ++query_id;
read(x1);read(y1);read(x2);read(y2);
//将所有的询问做成前缀和差分的形式
a[++cnt] = (Node){op,x2,y2,1,x};
a[++cnt] = (Node){op,x1-1,y2,-1,x};
a[++cnt] = (Node){op,x2,y1-1,-1,x};
a[++cnt] = (Node){op,x1-1,y1-1,1,x};
}
}
solve(1,cnt);
for(int i=1;i<=query_id;++i){
printf("%d\n",anss[i]);
}
getchar();getchar();
return 0;
}