CF19Dポイント

\(まず\) 離散

大きすぎる座標

離散考えてみましょう

\(第二\) セグメントツリー

3回の操作で定義されたデカルト座標系において:

質問の意味によって、この文は、これは、データ構造であると考えることは非常に簡単であること

\(1 <= N - <=2⋅105 ^ \)\(\ RIGHTARROW \)まで\(2⋅10^ 5 \)番目の横軸

それぞれについて、(X_I \)\に対応する({Y_I} _ {maxの\ } \) を維持するために、我々セグメントツリーを

3.find XY:すべてがタグ付けされたと右上の点(x、y)に、最も左側の点、そうでない場合のみポイントは、ポイントの底部を選択見つけ、ポイントの要件を満たしていない場合は、与えられました「 - 1」は、そうでなければX yを与えられました。

Jiangzi、我々はバイナリセグメントツリー缶\(\ RIGHTARROW \)\(logN個\)時間複雑内に操作を完了するためには、(3 \)\

操作\(1 \) \(2 \)だけ変更\(X \)\(Y_I {maxは}} _ {\)\(\ RIGHTARROW \)シングルポイント修飾

\(さらに\) \(セット\)

たぶん、あなたはこれがあることを考えます

操作:しかし、あなたはポイント逃した\(1 \) \(2 \)変更するかどうかを

いくつかの大規模なデータ構造は、それぞれの神を言って出てくる(X \)\\(のy \)私たちはバランスの取れたツリーを構築します

サポートインサートは、最大を維持し、削除します

実際には、\(セット\)は、完全にこれらの操作を実現することができます

\(最後に\)

この質問は、多くの場合、カードを持っている傾向があることです

セグメントツリー\(+ \)木の残高は、いくつかの後のように見えます

セグメントツリー\(+ \) \(SET \) \(+ \)のみの直接半\(A51 \)ポイント

セグメントツリー\(+ \) \(SET \) \(+ \)するセグメントツリー半分\(AC \)

\(コード\)

\(ACコード\)

#include <map>
#include <set>
#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define reg register
const int MAXN = 2e5 + 10;
struct node {
    int sit,x,y;
    void assignedment(int SIT) {
        sit = SIT;
    }
};
int T,Right,seg[MAXN];
set<int> st[MAXN];
node option[MAXN];
map<string,int> mp;
map<int,int> past_x,past_y;
//记录以前的值  
namespace pre {
    pair<int,int> a[MAXN],b[MAXN];
    inline void init() {
        mp["add"] = 1,mp["find"] = 2,mp["remove"] = 3;
        scanf("%d",&T);
        for(reg int i = 1; i <= T; i++) {
            string sit;
            cin >> sit;
            int x,y;
            scanf("%d%d",&x,&y);
            a[i] = make_pair(x,i);
            b[i] = make_pair(y,i);
            option[i].assignedment(mp[sit]);
        }
    }
    inline void hash() {
        sort(a + 1,a + 1 + T);
        sort(b + 1,b + 1 + T);
        int va,vb;
        va = vb = 0;
        for(reg int i = 1; i <= T; i++) {
            if(i == 1||a[i].first > a[i - 1].first) va++;
            if(i == 1||b[i].first > b[i - 1].first) vb++;
            option[a[i].second].x = va;
            past_x[va] = a[i].first;
            past_y[vb] = b[i].first;
            option[b[i].second].y = vb;
        }
        Right = va;
    }
    //输入及离散化 
}
namespace segment {
    int tree[MAXN << 2];
    inline void change(int l,int r,int k,int pos,int x) {
        if(l == r&&l == pos) {
            tree[k] = x;
            return;
        }
        int mid = l + r >> 1;
        if(pos <= mid) change(l,mid,k << 1,pos,x);
        else change(mid + 1,r,k << 1 | 1,pos,x);
        tree[k] = max(tree[k << 1],tree[k << 1 | 1]);
    }
    inline int query(int l,int r,int k,int ql,int qr) {
        if(ql <= l&&r <= qr)
            return tree[k];
        int mid = l + r >> 1,k1,k2;
        k1 = k2 = -1;
        if(ql <= mid) k1 = query(l,mid,k << 1,ql,qr);
        if(qr > mid) k2 = query(mid + 1,r,k << 1 | 1,ql,qr);
        return max(k1,k2);
    }
    //线段树 
    inline int findans(int l,int r,int k,int pos,int x)
    {
        if(l == r) return l;
        int mid = l + r >> 1,k1,k2;
        k1 = k2 = Right + 1;
        if(pos < mid&&tree[k << 1] > x) k1 = findans(l,mid,k << 1,pos,x);
        if(k1 < Right + 1) return k1;
        //这一句必须加 不然T(左边已经找到了 没必要找右边的) 
        if(tree[k << 1 | 1] > x) k2 = findans(mid + 1,r,k << 1 | 1,pos,x);
        return min(k1,k2);
    }
    //线段树上的二分 
}
inline void solve() {
    for(reg int i = 1; i <= T; i++) {
        switch(option[i].sit) {
            case 1: {
                if(st[option[i].x].size() == 0)
                    segment::change(1,Right,1,option[i].x,option[i].y);
                else {
                    auto it = st[option[i].x].end();
                    if(option[i].y > *(--it)) segment::change(1,Right,1,option[i].x,option[i].y);
                }
                st[option[i].x].insert(option[i].y);
                //加点 用set 
                break;
            }
            case 2: {
                int l = option[i].x + 1,r = Right;
                int res = segment::query(1,Right,1,l,r);
                if(res <= option[i].y) printf("-1\n");
                else {
                    int j = segment::findans(1,Right,1,option[i].x,option[i].y);
                    printf("%d %d\n",past_x[j],past_y[*(st[j].upper_bound(option[i].y))]);
                }
                //求答案 
                break;
            }
            case 3: {
                auto it = st[option[i].x].upper_bound(option[i].y);
                bool f = 0;
                if(it == st[option[i].x].end()) f = 1;
                st[option[i].x].erase((--it));
                if(f) {
                    int pas;
                    if(st[option[i].x].size() == 0)
                        pas = 0;
                    else {
                        auto it = st[option[i].x].end();
                        pas = *--it;
                    }
                    segment::change(1,Right,1,option[i].x,pas);
                }
                //删点 用set 
                break;
            }
        }
    }
}
int main() {
    pre::init();
    pre::hash();
    solve();
    return 0;
}

\(TLEコード\)

#include <map>
#include <set>
#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define reg register
const int MAXN = 2e5 + 10;
struct node {
    int sit,x,y;
    void assignedment(int SIT) {
        sit = SIT;
    }
};
int T,Right,seg[MAXN];
set<int> st[MAXN];
node option[MAXN];
map<string,int> mp;
map<int,int> past_x,past_y;
namespace pre {
    pair<int,int> a[MAXN],b[MAXN];
    inline void init() {
        mp["add"] = 1,mp["find"] = 2,mp["remove"] = 3;
        scanf("%d",&T);
        for(reg int i = 1; i <= T; i++) {
            string sit;
            cin >> sit;
            int x,y;
            scanf("%d%d",&x,&y);
            a[i] = make_pair(x,i);
            b[i] = make_pair(y,i);
            option[i].assignedment(mp[sit]);
        }
    }
    inline void hash() {
        sort(a + 1,a + 1 + T);
        sort(b + 1,b + 1 + T);
        int va,vb;
        va = vb = 0;
        for(reg int i = 1; i <= T; i++) {
            if(i == 1||a[i].first > a[i - 1].first) va++;
            if(i == 1||b[i].first > b[i - 1].first) vb++;
            option[a[i].second].x = va;
            past_x[va] = a[i].first;
            past_y[vb] = b[i].first;
            option[b[i].second].y = vb;
        }
        Right = va;
    }
}
namespace segment {
    int tree[MAXN << 2];
    inline void change(int l,int r,int k,int pos,int x) {
        if(l == r&&l == pos) {
            tree[k] = x;
            return;
        }
        int mid = l + r >> 1;
        if(pos <= mid) change(l,mid,k << 1,pos,x);
        else change(mid + 1,r,k << 1 | 1,pos,x);
        tree[k] = max(tree[k << 1],tree[k << 1 | 1]);
    }
    inline int query(int l,int r,int k,int ql,int qr) {
        if(ql <= l&&r <= qr)
            return tree[k];
        int mid = l + r >> 1,k1,k2;
        k1 = k2 = -1;
        if(ql <= mid) k1 = query(l,mid,k << 1,ql,qr);
        if(qr > mid) k2 = query(mid + 1,r,k << 1 | 1,ql,qr);
        return max(k1,k2);
    }
}
inline void solve() {
    for(reg int i = 1; i <= T; i++) {
        switch(option[i].sit) {
            case 1: {
                if(st[option[i].x].size() == 0)
                    segment::change(1,Right,1,option[i].x,option[i].y);
                else {
                    auto it = st[option[i].x].end();
                    if(option[i].y > *(--it)) segment::change(1,Right,1,option[i].x,option[i].y);
                }
                st[option[i].x].insert(option[i].y);
                break;
            }
            case 2: {
                int l = option[i].x + 1,r = Right;
                int res = segment::query(1,Right,1,l,r);
                if(res <= option[i].y) printf("-1\n");
                else {
                    while(l < r) {
                        int mid = l + r >> 1;
                        int res = segment::query(1,Right,1,l,mid);
                        if(res > option[i].y) r = mid;
                        else l = mid + 1;
                    }
                    int j = l;
                    printf("%d %d\n",past_x[j],past_y[*(st[j].upper_bound(option[i].y))]);
                }
                
                //与上面AC的代码不一样的只有这里 上面是在树上二分的 时间复杂度O(logn) 而这里直接二分+线段树求区间最大值O(log^2n)
                break;
            }
            case 3: {
                auto it = st[option[i].x].upper_bound(option[i].y);
                bool f = 0;
                if(it == st[option[i].x].end()) f = 1;
                st[option[i].x].erase((--it));
                if(f) {
                    int pas;
                    if(st[option[i].x].size() == 0)
                        pas = 0;
                    else {
                        auto it = st[option[i].x].end();
                        pas = *--it;
                    }
                    segment::change(1,Right,1,option[i].x,pas);
                }
                break;
            }
        }
    }
}
int main() {
    pre::init();
    pre::hash();
    solve();
    return 0;
}

おすすめ

転載: www.cnblogs.com/resftlmuttmotw/p/11622607.html