0828考试总结

0828考试总结

​ 考崩了,本来以为自己可以考到190或者更高分,实则就拿到了30分。T1统计答案有点问题,最简单的题就拿了30分。T2复杂度没有问题,将点标记上出了问题,爆0了。T3的30分暴力分也没拿到。

T1

​ 是一道枚举+乱搞的题。

​ 先枚举根节点,然后贪心的处理处每个节点的最小深度,暴力统计答案就好。

T2

​ STL。

​ 用到了\(map\)\(multiset\),炒鸡香,既简单又便捷。

​ mp.insert(a):在mp里插入一个值a;

​ mp.lower_bound(a):返回mp种第一个大于等于a的迭代器指针;

​ mp.upper_bound(a):返回mp中第一个大于a的迭代器指针;

​ mp.begin():头; mp.end():尾的后一个。

\(multiset\)插入一个数,删除一个数都是\(O(logn)\)的,它可以保证序列中的数是有序的,序列中可以有重复的数。

​ mset.insert(a):插入一个数a;

​ mset.erase(a):删除一个数a;

​ mset.begin():头; mset.end():尾的后一个;

​ mset.size():返回当前的元素数量;

​ mset.erase(beg, end):移除区间[beg,end)中所有的元素。

#include <bits/stdc++.h>
	
using namespace std;
	
inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e5 + 5;
int n, m;
map <int, multiset<int> > mx, my;

void init() {
    n = read(); m = read();
    for(int i = 1, x, y;i <= n; i++) {  
        x = read(); y = read();
        mx[x].insert(y);
        my[y].insert(x);
    }
}

void work() {
    for(int i = 1, o, n1, n2;i <= m; i++) {
        o = read(); n1 = read(); n2 = read();
        int tot = 0;
        if(o == 0) {
            map <int, multiset<int> > :: iterator it, it1, it2;
            it1 = mx.lower_bound(n1);
            it2 = mx.upper_bound(n2);
            for(it = it1; it != it2; it++) {
                multiset<int> &now = (it -> second);
                int x = (it -> first);
                tot += now.size();
                for(multiset <int> :: iterator it = now.begin(); it != now.end(); it++) {
                    int y = *it; 
                    my[y].erase(x);
                }
            }
            mx.erase(it1, it2);
        }
        if(o == 1) {
            map <int, multiset<int> > :: iterator it, it1, it2;
            it1 = my.lower_bound(n1);
            it2 = my.upper_bound(n2);
            for(it = it1; it != it2; it++) {
                multiset<int> &now = (it -> second);
                int y = (it -> first);
                tot += now.size();
                for(multiset <int> :: iterator it = now.begin(); it != now.end(); it++) {
                    int x = *it;
                    mx[x].erase(y);
                }
            }
            my.erase(it1, it2);
        }
        printf("%d\n", tot);
    }
}

int main() {

    freopen("city.in","r",stdin); freopen("city.out","w",stdout);

    init();
    work();

    fclose(stdin); fclose(stdout);
    return 0;
}

T3

​ 动态开点线段树+线段树合并。(我吐了)

​ 我太弱了,不咋会。

​ 这道题是在树上找两条最长上升的链,用权值线段树维护一下最长上升的链的长度。

#include <bits/stdc++.h>

#define mid ((l + r) >> 1)

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e5 + 5, inf = 1e9;
int n, cnt, ans, tot;
int root[N][2];
vector<int> e[N];
struct node { int fa, val; } a[N];
struct tree { int ls, rs, sum; } t[N << 2];

void init() {
    n = read();
    for(int i = 1;i <= n; i++) {
        a[i].val = read(); a[i].fa = read();
        if(a[i].fa) e[a[i].fa].push_back(i);
    }
}

void insert(int &o, int l, int r, int p, int w) {
    if(!o) o = ++tot;
    t[o].sum = max(t[o].sum, w);
    if(l == r) return ;
    if(p <= mid) insert(t[o].ls, l, mid, p, w);
    if(p > mid) insert(t[o].rs, mid + 1, r, p, w);
}

int query(int o, int l, int r, int x, int y) {
    int res = 0;
    if(!o) return 0;
    if(l >= x && r <= y) return t[o].sum;
    if(x <= mid) res = max(res, query(t[o].ls, l, mid, x, y));
    if(y > mid) res = max(res, query(t[o].rs, mid + 1, r, x, y));
    return res;
}

void merge(int &l, int r) {
    if(!l) { l = r; return ; }
    if(!r) return ;
    t[l].sum = max(t[l].sum, t[r].sum);
    merge(t[l].ls, t[r].ls);
    merge(t[l].rs, t[r].rs);
}  

void dfs(int x) {
    insert(root[x][0], 0, inf, a[x].val, 1); 
    insert(root[x][1], 0, inf, a[x].val, 1); //在权值线段树上插入一个新节点
    int tmp1 = 0, tmp2 = 0;
    for(int i = 0; i < (int)e[x].size(); i++) {
        int y = e[x][i]; dfs(y);
        tmp1 = max(tmp1, query(root[y][0], 0, inf, 0, a[x].val - 1)); //询问最大值
        tmp2 = max(tmp2, query(root[y][1], 0, inf, a[x].val + 1, inf));
        merge(root[x][0], root[y][1]); //合并父亲和儿子的信息
        merge(root[x][1], root[y][1]);
    }
    insert(root[x][0], 0, inf, a[x].val, tmp1 + 1);
    insert(root[x][1], 0, inf, a[x].val, tmp2 + 1);
    ans = max(ans, tmp1 + tmp2 + 1);
}

void work() {
    dfs(1);
    printf("%d", ans);
}

int main() {

    // freopen("lil.in","r",stdin); freopen("lil.out","w",stdout);

    init();
    work();

    // fclose(stdin); fclose(stdout);
    return 0;
}

posted @ 2020-08-29 06:18  C锥  阅读(104)  评论(0编辑  收藏  举报