1. 程式人生 > >HDU 5517 【二維樹狀數組///三維偏序問題】

HDU 5517 【二維樹狀數組///三維偏序問題】

void blog scan memset 集合 while ++ struct name

題目鏈接:【http://acm.split.hdu.edu.cn/showproblem.php?pid=5517】

題意:定義multi_set A<a , d>,B<c , d , e>,C<x , y , z>,給出 A , B ,定義 C = A * B = ={?a,c,d??a,b?A, ?c,d,e?B and b=e}求出C之後,求C中一個元素t[i]<a , b , c>是否存在一個元素tmp<x , y , z>使得 x >= a&&y > =b&&z >= c && t != tmp;如果不存在ans++;輸出ans即可。

題解:

  首先,我們要剪枝和去重,加入集合A中存在<1 , 3>,<2, 3>,<3, 3> ,<4, 3>,<4, 3>,那麽只需要保留<4,3>就可以了,並且記錄一下數量。因為前面的數都可以找到比它大的元素。求出C之後,我們依舊要對C去重。那麽這道題就是求C某個元素是否存在大於它的元素了。因為這道題中B set裏面c,d,很小在生成的C中y,z也很小,都小於1000,那麽我們就可以用二維樹狀數組做了。首先對C進行從大到小排序,樹狀數組中只記錄y,z的值。我們枚舉C中的額每一個元素,先查詢(1001 - y ,1001 - z),然後在更新(1001 - y ,1001 - z),應為是從大到小排序的,所以後面的元素的x值一定小於等於前面的元素的x值,s如果查詢不為0,那麽一定存在某個元素是大於它的。我們一可以直接套CDQ分治的三維偏序模板,為維護值即可。

樹狀數組:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 15;
int ic, N, M;
struct Point
{
    int x, y, z;
    LL w;
    Point() {}
    Point(int x, int y, int z, LL w): x(x), y(y), z(z), w(w) {}
    bool operator < (const Point& T) const
    {
        if(x != T.x) return T.x < x;
        if(y != T.y) return T.y < y;
        return T.z < z;
    }
    bool operator == (const Point T) const
    {
        return (x == T.x && y == T.y && z == T.z);
    }
} P[maxn];
int T[maxn], C[maxn];
int Tbit[1050][1050];
int low_bit(int x)
{
    return x & -x;
}
void Bit_add(int x, int y, int val)
{
    for(int i = x; i <= 1001; i += low_bit(i))
        for(int j = y; j <= 1001; j += low_bit(j))
            Tbit[i][j] += val;
}
int Bit_sum(int x, int y)
{
    int ret = 0;
    for(int i = x; i; i -= low_bit(i))
        for(int j = y; j; j -= low_bit(j))
            ret += Tbit[i][j];
    return ret;
}
int main ()
{
    scanf("%d", &ic);
    for(int cs = 1; cs <= ic; cs++)
    {
        scanf("%d %d", &N, &M);
        memset(T, 0, sizeof(T));
        for(int i = 1; i <= N; i++)
        {
            int a, b;
            scanf("%d %d", &a, &b);
            if(a > T[b]) T[b] = a, C[b] = 1;
            else if(a == T[b]) C[b]++;
        }
        int tmp = 0;
        for(int i = 1; i <= M; i++)
        {
            int a, b, c;
            scanf("%d %d %d", &a, &b, &c);
            if(T[c]) P[++tmp] = Point(T[c], a, b, (LL)C[c]);
        }
        sort(P + 1, P + 1 + tmp);
        N = 1;
        for(int i = 2; i <= tmp; i++)
        {
            if(P[i] == P[N]) P[N].w += P[i].w;
            else
                P[++N] = P[i];
        }
        LL ans = 0;
        memset(Tbit, 0, sizeof(Tbit));
        for(int i = 1; i <= N; i++)
        {
            if(!Bit_sum(1001 - P[i].y, 1001 - P[i].z)) ans += P[i].w;
            Bit_add(1001 - P[i].y, 1001 - P[i].z, 1);
        }
        printf("Case #%d: %lld\n", cs, ans);
    }
    return 0;
}

三維偏序:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 15;
int cs, N, M;
int T[maxn], C[maxn];
LL W[maxn], ans[maxn];
struct Edge
{
    int x, y, z, id;
    LL w;
    Edge() {}
    Edge(int x, int y, int z, int id, LL w): x(x), y(y), z(z), id(id), w(w) {}
    bool operator < (const Edge & T) const
    {
        return z < T.z;
    }
    bool operator == (const Edge & T) const
    {
        return T.x == x && T.y == y && T.z == z;
    }
} B[maxn], p[maxn], t[maxn];
bool cmpx(Edge &a, Edge &b)
{
    if(a.x == b.x && a.y == b.y && a.z == b.z)
        return a.id < b.id;
    else if(a.x == b.x && a.y == b.y)
        return a.z  < b.z;
    else if(a.x == b.x)
        return a.y  < b.y;
    else
        return a.x  < b.x;
}
bool cmpy(Edge &a, Edge &b)
{
    if( a.y == b.y && a.z == b.z)
        return a.id < b.id;
    else if(a.y == b.y)
        return a.z  < b.z;
    else
        return a.y  < b.y;
}
//--------------------------------------------------------//樹狀數組
int c[maxn], maxz = 1001;
inline int lowbit(int x)
{
    return x & (-x);
}
void add(int x, int val)
{
    while(x <= maxz) c[x] += val, x += lowbit(x);
}
int Get_sum(int x)
{
    int ret = 0;
    while(x > 0) ret += c[x], x -= lowbit(x);
    return ret;
}
//-------------------------------------------------
void cdq(int l, int r)
{
    if(l == r) return ;
    int mid = (l + r) / 2;
    cdq(l, mid), cdq(mid + 1, r);
    for(int i = l; i <= r; i++) t[i] = p[i];
    sort(t + l, t + mid + 1, cmpy), sort(t + mid + 1, t + r + 1, cmpy);
    int a1 = l, a2 = mid + 1;
    for(int i = l; i <= r; i++)
    {
        if(a1 == mid + 1)
            ans[t[a2].id] += Get_sum(t[a2].z), a2++;
        else if(a2 == r + 1)
            add(t[a1].z, 1), a1++;
        else if(t[a1].y <= t[a2].y)
            add(t[a1].z, 1), a1++;
        else
            ans[t[a2].id] += Get_sum(t[a2].z), a2++;
    }
    for(int i = l; i <= mid; i++) add(t[i].z, -1);
}
int main ()
{
    scanf("%d", &cs);
    for(int ic = 1; ic <= cs; ic++)
    {
        memset(T, 0, sizeof(T));
        memset(ans, 0, sizeof(ans));
        scanf("%d %d", &N, &M);
        for(int i = 1; i <= N; i++)
        {
            int a, b;
            scanf("%d %d", &a, &b);
            if(a > T[b]) T[b] =  a, C[b] = 1;
            else if(a == T[b]) C[b]++;
        }
        int tmp = 0;
        for(int i = 1; i <= M; i++)
        {
            int a, b, c;
            scanf("%d %d %d", &a, &b, &c);
            if(T[c]) ++tmp, p[tmp] = Edge(T[c], a, b, i, (LL)C[c]);
        }
        sort(p + 1, p + 1 + tmp, cmpx);
        N = 1;
        for(int i = 2; i <= tmp; i++)
        {
            if(p[i] == p[N]) p[N].w += p[i].w;
            else p[++N] = p[i];
        }
        if(N <= 1)
        {
            printf("Case #%d: 0\n", ++ic);
            continue;
        }
        for(int i = 1; i <= N; i++)
        {
            p[i].x = 100001 - p[i].x;
            p[i].y = 1001 - p[i].y;
            p[i].z = 1001 - p[i].z;
        }
        for(int i = 1; i <= N; i++)
        {
            p[i].id = i;
            W[i] = p[i].w;
        }
        sort(p + 1, p + 1 + N, cmpx);
        cdq(1, N);
        p[N + 1].x = -1;
        for(int i = N; i >= 1; i--)
        {
            if(p[i].x == p[i + 1].x && p[i].y == p[i + 1].y && p[i].z == p[i + 1].z)
                ans[p[i].id] = ans[p[i + 1].id];
        }
        LL ret = 0;
        for(int i = 1; i <= N; i++) if(!ans[i]) ret += W[i];
        printf("Case #%d: %lld\n", ic, ret);
    }
    return 0;
}

  

HDU 5517 【二維樹狀數組///三維偏序問題】