杂题小记(2023.02.24)

杂题小记(2023.02.24)

更好的阅读体验戳此进入

LG-P5251 [LnOI2019]第二代图灵机

题面

维护一堆奇奇怪怪的东西。

Solution

考虑线段树维护权值,支持单点修改区间 $ \max $ 和区间 $ \min $,ODT 维护颜色,然后在 ODT 上做双指针并在线段树上查询即可,细节巨多,双指针边界需要精细考虑并实现,还感觉有点类似莫队的思想,好题

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define LIM (110000)
#define INF (0x3f3f3f3f)

template < typename T = int >
inline T read(void);

int N, M, C;
int val[LIM], col[LIM];
int cnt[110];

class SegTree{
private:
    int sum[LIM << 2], mn[LIM << 2], mx[LIM << 2];
    #define LS (p << 1)
    #define RS (LS | 1)
    #define MID ((gl + gr) >> 1)
public:
    SegTree(void){memset(mn, 0x3f, sizeof mn);}
    void Pushup(int p){
        sum[p] = sum[LS] + sum[RS];
        mn[p] = min(mn[LS], mn[RS]);
        mx[p] = max(mx[LS], mx[RS]);
    }
    void Build(int p = 1, int gl = 1, int gr = N){
        if(gl == gr)return sum[p] = mn[p] = mx[p] = val[gl = gr], void();
        Build(LS, gl, MID), Build(RS, MID + 1, gr);
        Pushup(p);
    }
    void Modify(int pos, int val, int p = 1, int gl = 1, int gr = N){
        if(gl == gr)return sum[p] = mn[p] = mx[p] = val, void();
        if(pos <= MID)Modify(pos, val, LS, gl, MID);
        else Modify(pos, val, RS, MID + 1, gr);
        Pushup(p);
    }
    int QuerySum(int l, int r, int p = 1, int gl = 1, int gr = N){
        if(l <= gl && gr <= r)return sum[p];
        if(l > gr || r < gl)return 0;
        return QuerySum(l, r, LS, gl, MID) + QuerySum(l, r, RS, MID + 1, gr);
    }
    int QueryMin(int l, int r, int p = 1, int gl = 1, int gr = N){
        if(l <= gl && gr <= r)return mn[p];
        if(l > gr || r < gl)return INF;
        return min(QueryMin(l, r, LS, gl, MID), QueryMin(l, r, RS, MID + 1, gr));
    }
    int QueryMax(int l, int r, int p = 1, int gl = 1, int gr = N){
        if(l <= gl && gr <= r)return mx[p];
        if(l > gr || r < gl)return 0;
        return max(QueryMax(l, r, LS, gl, MID), QueryMax(l, r, RS, MID + 1, gr));
    }
}st;

struct Node{
    int l, r;
    mutable int val;
    friend const bool operator < (const Node &a, const Node &b){
        return a.l < b.l;
    }
};

class ODT{
private:
    set < Node > tr;
public:
    auto Insert(Node p){return tr.insert(p);}
    auto Split(int p){
        auto it = tr.lower_bound(Node{p});
        if(it != tr.end() && it->l == p)return it;
        advance(it, -1);
        if(it->r < p)return tr.end();
        auto l = it->l, r = it->r, val = it->val;
        tr.erase(it);
        Insert(Node{l, p - 1, val});
        return Insert(Node{p, r, val}).first;
    }
    void Assign(int l, int r, int val){
        auto itR = Split(r + 1), itL = Split(l);
        tr.erase(itL, itR);
        Insert(Node{l, r, val});
    }
    int Query3(int l, int r){
        if(C == 1)return st.QueryMin(l, r);
        int ans(INT_MAX);
        int tot(0);
        auto itR = Split(r + 1), itL = Split(l);
        auto itl = itL, itr = itL;
        while(itl != itR){
            while(tot < C && itr != itR)if(!cnt[(itr++)->val]++)++tot;
            if(tot == C){
                while(cnt[itl->val] > 1)--cnt[(itl++)->val];
                ans = min(ans, st.QuerySum(itl->r, prev(itr)->l));
                while(tot == C && itl != itR)if(!--cnt[(itl++)->val])--tot;
            }
            if(itr == itR)while(itl != itR)--cnt[(itl++)->val];
        }return ans == INT_MAX ? -1 : ans;
    }
    int Query4(int l, int r){
        int ans = st.QueryMax(l, r);
        auto itR = Split(r + 1), itL = Split(l);
        auto itl = itL, itr = itL;
        while(itl != itR){
            while(itr != itR && itr->r - itr->l + 1 == 1 && !cnt[itr->val])cnt[(itr++)->val]++;
            if(itr != itR && itr->r - itr->l + 1 > 1){
                if(!cnt[itr->val])ans = max(ans, st.QuerySum(itl->r, itr->l));
                else if(itl != itr){
                    ans = max(ans, st.QuerySum(itl->r, prev(itr)->l));
                    while(cnt[itr->val])cnt[(itl++)->val]--;
                    ans = max(ans, st.QuerySum(itl->r, itr->l));
                }
                while(itl != itr)cnt[(itl++)->val]--;
                cnt[(itr++)->val]++;
                continue;
            }
            if(itl != itr){
                ans = max(ans, st.QuerySum(itl->r, prev(itr)->l));
                if(itr == itR)while(itl != itR)cnt[(itl++)->val]--;
                else while(itl != itR && cnt[itr->val])cnt[(itl++)->val]--;
            }
        }return ans;
    }
}odt;

int main(){
    N = read(), M = read(), C = read();
    for(int i = 1; i <= N; ++i)val[i] = read();
    for(int i = 1; i <= N; ++i)col[i] = read(), odt.Insert(Node{i, i, col[i]});
    st.Build();
    while(M--){
        int opt = read();
        switch(opt){
            case 1:{
                int p = read(), v = read();
                st.Modify(p, v);
                break;
            }
            case 2:{
                int l = read(), r = read(), v = read();
                odt.Assign(l, r, v);
                break;
            }
            case 3:{
                int l = read(), r = read();
                printf("%d\n", odt.Query3(l, r));
                break;
            }
            case 4:{
                int l = read(), r = read();
                printf("%d\n", odt.Query4(l, r));
                break;
            }
            default:break;
        }
    }
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P3765 总统选举

题面

给定 $ n $ 个人的投票,$ m $ 次询问给定 $ l, r, s, k $ 求 $ [l, r] $ 区间严格众数,若不存在则认为为 $ s $,并给定 $ k $ 个数将这些人的投票均改为求出的严格众数,每次输出求得的区间严格众数,特别地,所有操作完成后需要再对 $ [1, n] $ 求一次区间严格众数,不存在则输出 -1

Solution

首先摩尔投票默认为前置知识不再提了,不难发现区间众数不支持合并,而摩尔众数形式表示的区间众数则支持,合并是平凡的,则开一颗权值线段树即可。同时考虑验证部分,不难想到对每个人开一个平衡树记录有哪些人对其投票了,这样可以支持动态修改,然后每次查询一下 $ [l, r] $ 内有多少并与总长度比较判断即可。值得一提的是不难发现本题平衡树功能平凡,于是考虑直接使用 tree < int, null_type, less < int >, rb_tree_tag, tree_order_statistics_node_update > 维护即可,可以大幅减少码量以及错误率,但时间上略有降低。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template < typename T = int >
inline T read(void);

int N, M;
int vote[510000];
tree < int, null_type, less < int >, rb_tree_tag, tree_order_statistics_node_update > tr[510000];

class SegTree{
private:
    int tr[510000 << 2], cnt[510000 << 2];
    #define LS (p << 1)
    #define RS (LS | 1)
    #define MID ((gl + gr) >> 1)
public:
    pair < int, int > Merge(pair < int, int > l, pair < int, int > r){
        if(l.first == r.first)return {l.first = r.first, l.second + r.second};
        if(l.second >= r.second)return {l.first, l.second - r.second};
        else return {r.first, r.second - l.second};
    }
    void Pushup(int p){
        tie(tr[p], cnt[p]) = Merge({tr[LS], cnt[LS]}, {tr[RS], cnt[RS]});
    }
    void Build(int p = 1, int gl = 1, int gr = N){
        if(gl == gr)return tr[p] = vote[gl = gr], cnt[p] = 1, void();
        Build(LS, gl, MID), Build(RS, MID + 1, gr);
        Pushup(p);
    }
    void Modify(int pos, int p = 1, int gl = 1, int gr = N){
        if(gl == gr)return tr[p] = vote[gl = gr], void();
        if(pos <= MID)Modify(pos, LS, gl, MID);
        else Modify(pos, RS, MID + 1, gr);
        Pushup(p);
    }
    pair < int, int > Query(int l, int r, int p = 1, int gl = 1, int gr = N){
        if(l <= gl && gr <= r)return {tr[p], cnt[p]};
        pair < int, int > ret{0, -1};
        if(l <= MID)ret = Merge(Query(l, r, LS, gl, MID), ret);
        if(r >= MID + 1)ret = Merge(Query(l, r, RS, MID + 1, gr), ret);
        return ret;
    }
}st;

int main(){
    N = read(), M = read();
    for(int i = 1; i <= N; ++i)tr[vote[i] = read()].insert(i);
    st.Build();
    while(M--){
        int l = read(), r = read(), s = read(), k = read();
        auto win = st.Query(l, r).first;
        int rnkR = tr[win].order_of_key(r);
        if(*tr[win].find_by_order(rnkR) != r)--rnkR;
        int rnkL = tr[win].order_of_key(l);
        if(rnkR - rnkL + 1 > ((r - l + 1) >> 1))s = win;
        while(k--){
            int p = read();
            tr[vote[p]].erase(p), tr[s].insert(p);
            vote[p] = s, st.Modify(p);
        }printf("%d\n", s);
    }
    int l = 1, r = N, s = -1;
    auto win = st.Query(l, r).first;
    int rnkR = tr[win].order_of_key(r);
    if(*tr[win].find_by_order(rnkR) != r)--rnkR;
    int rnkL = tr[win].order_of_key(l);
    if(rnkR - rnkL + 1 > ((r - l + 1) >> 1))s = win;
    printf("%d\n", s);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2023_02_24 初稿

posted @ 2023-03-05 12:48  Tsawke  阅读(6)  评论(0编辑  收藏  举报