【BOI2007】BZOJ1176 CDQ分治

啊最近准备初赛,这星期再进机房一步,直播吃屎

CDQ分治,就是对询问和修改离线后分治解答

这道题就是一道很简单的CDQ分治,大概思路就是下面这段代码

inline void solve (int l,int r) {
if ( l == r ) return ;

solve(l,mid);

solve(mid+1,r);

merge(l,r);

}


做法:

1、将一个询问拆分成四个询问,把询问和修改一起CDQ分治

2、递归完成后将左侧的修改和右侧的询问按照y为关键词排序,依次加入树状数组。


Tips:题目描述有点小问题,翻译过来应该是所有的点初值都是0,但这并不影响答案

#include <cassert>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
 
#define N 3000050
 
using namespace std;
 
typedef int LL;
 
struct Monster{ int x,y,s,mk,rank;LL ans; }Q[N];
bool cmp1(Monster p1,Monster p2 ){  return p1.y < p2.y; }
bool cmp2(Monster p1,Monster p2) {  return p1.rank < p2.rank; }
int w,n,cmd;
 
 
 
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
 
 
int lowbit(int x) { return (x & (-x)); }
 
struct Small_Segment_Tree{
    LL tr[N]; vector<int> tmp;
    inline void add(int x,LL v) {   
        for (int i=x;i<=w;i+=lowbit(i)) {
            tr[i] += v ;
            tmp.push_back(i); 
        } 
    }
    inline LL ask(int x) { 
        LL sum = 0; 
        for (int i=x;i>=1;i-=lowbit(i)) sum += tr[i]; 
        return sum; 
    }
    inline void clear() {
        for (int i=0;i<tmp.size();i++) tr[ tmp[i] ] = 0;
        tmp.clear();
    }
}T;
 
inline void init(int &cmd) {
    if (cmd == 1) {
        Q[++n].x = read(), Q[n].y = read();
        Q[n].s = read();
        Q[n].mk = 1;
    } else {
        int x1 = read()-1 , y1 = read()-1 , x2 = read() , y2 = read();
        Q[++n].x = x1 , Q[n].y = y1; Q[n].mk = 2; 
        Q[++n].x = x1 , Q[n].y = y2;
        Q[++n].x = x2 , Q[n].y = y1;
        Q[++n].x = x2 , Q[n].y = y2;
    }
    return ;
}
 
inline void merge(int l,int r,int mid) {
    //memset(T.tr,0,sizeof(T.tr));
    sort(Q+l,Q+mid+1,cmp1);
    sort(Q+mid+1,Q+r+1,cmp1);
    T.clear();
     
    int i = l;
    for (int j=mid+1;j<=r;j++) if (Q[j].mk != 1) {
        while (i<=mid && Q[i].y <= Q[j].y) {
            if (Q[i].mk == 1) T.add(Q[i].x , Q[i].s);
            i++;
        }
        Q[j].ans += T.ask(Q[j].x);
    } 
     
}
 
void solve(int l,int r) {
    if (l == r) return ;
    int mid = (l + r) >> 1;
    solve(l,mid);
    solve(mid+1,r);
    merge(l,r,mid);
} 
 
 
int main()
{
    read();  w = read();
     
    while (( cmd = read() ) != 3) init(cmd);
    for (int i=1;i<=n;i++) Q[i].rank = i;
    solve(1,n);
    sort(Q+1,Q+n+1,cmp2);
     
    for (int i=1;i<=n;i++) if (Q[i].mk == 2) {
        LL ans = Q[i+3].ans - Q[i+2].ans - Q[i+1].ans + Q[i].ans;
        printf("%d\n",ans);
    }
     
    //debug();
     
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值