ACdream--1157(CDQ分治)

2015-08-09 18:48:32

传送门】CDQ第二道启蒙题~

题意:有最多10^5种操作,每种操作可以是(1)添加一条线段【L,R】,(2)删除第 i 条添加的线段,(3)查询有多少现存的线段完全包含【l,r】这条线段

思路:考虑CDQ分治,有BZOJ 1176的经验,可以先将所有操作按照左端点进行排序,然后将操作按照时间一分为二,先处理前半边修改对后半边询问造成的影响,由于已经按照左端点排过序了,我们可以用树状数组维护每个修改的右端点,加线段就给右端点处+1,删除就给右端点处-1,查询的话只要查右端点 r 的右边的右端点数就可以了(此时左端点一定被包含),由于端点值很大,需要提前离散化。

  处理这些影响后还原前半边操作的影响。

  然后按照时间把前半边操作放在左边,后半边操作放在右边,分别处理左 / 右半边操作。

 

#include <cstdio>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB push_back

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 200010;

int N,pos[MAXN],sz;
int c[MAXN],ans[MAXN];
int b[MAXN];

int lowbit(int x){ return x & (-x); }

void Update(int x,int d){
    while(x < MAXN){
        c[x] += d;
        x += lowbit(x);
    }
}

int Getsum(int x){
    int res = 0;
    while(x){
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

struct Node{
    int l,r,f,id;
    bool operator < (const Node &b) const{
        if(l == b.l) return f > b.f;
        return l < b.l;
    }
}P[MAXN],tmp[MAXN];

void CDQ(int l,int r){
    if(l == r) return;
    //l --> mid , mid + 1 --> r
    int mid = getmid(l,r);
    for(int i = l; i <= r; ++i){
        if(P[i].id <= mid && P[i].f == 0) Update(P[i].r,1);
        else if(P[i].id <= mid && P[i].f > 0) Update(P[i].r,-1);
        else if(P[i].id > mid && P[i].f == -1)
            ans[P[i].id] += Getsum(sz) - Getsum(P[i].r - 1);
    }
    for(int i = l; i <= r; ++i){
        if(P[i].id <= mid && P[i].f == 0) Update(P[i].r,-1);
        else if(P[i].id <= mid && P[i].f > 0) Update(P[i].r,1);
    }
    int c1 = l,c2 = mid + 1;
    for(int i = l; i <= r; ++i){
        if(P[i].id <= mid) tmp[c1++] = P[i];
        else tmp[c2++] = P[i];
    }
    for(int i = l; i <= r; ++i) P[i] = tmp[i];
    CDQ(l,mid);
    CDQ(mid + 1,r);
}

int main(){
    char s[10];
    while(scanf("%d",&N) != EOF){
        int cnt = 0;
        sz = 0;
        memset(ans,0,sizeof(ans));
        memset(c,0,sizeof(c));
        for(int i = 1; i <= N; ++i){
            scanf("%s%d",s,&P[i].l);
            if(s[0] == 'C'){ //
                P[i].f = P[i].l; //删第几条边
                P[i].l = P[pos[P[i].f]].l;
                P[i].r = P[pos[P[i].f]].r;
            }
            else{
                scanf("%d",&P[i].r);
                if(s[0] == 'D'){
                    pos[++cnt] = i;
                    P[i].f = 0; //
                }
                else{
                    P[i].f = -1; //
                }
            }
            P[i].id = i;
            b[++sz] = P[i].l;
            b[++sz] = P[i].r;
        }
        sort(b + 1,b + sz + 1);
        sz = unique(b + 1,b + sz + 1) - b - 1;
        for(int i = 1; i <= N; ++i){
            P[i].l = lower_bound(b + 1,b + sz + 1,P[i].l) - b;
            P[i].r = lower_bound(b + 1,b + sz + 1,P[i].r) - b;
        }
        sort(P + 1,P + N + 1);
        CDQ(1,N);
        for(int i = 1; i <= N; ++i) if(P[i].f == -1) printf("%d\n",ans[i]);
    }
    return 0;
}

 

posted @ 2015-08-09 18:56  Naturain  阅读(116)  评论(0编辑  收藏  举报