• [COCI]coci2015/2016 nekameleoni


    题意:

    初始数列,每个数都在1~k以内

    支持两种操作:1.修改一个数,修改后的数在1~k内

                              2.查询一个最短包含1~k的序列的长度

    查询100000,数列100000,k是50

    题解

    考虑压缩状态到一个二进制串。

    用一个线段树。每个点维护前缀的状态,后缀的状态。被包含的最短的

    然后如果暴力合并子树信息,这样是O(n^3log_2{n})的,其实有用的状态不超过O(k)个。那么时间复杂度就是O(k^2nlog_2{n})

    合并子树的时候尺取。

    就是O(knlog_2{n})。卡卡卡卡卡常大概好像就过了

    #include <cassert>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    
    using namespace std;
    
    #define FOR(i, a, b) for (int i = (a); i < (b); ++i)
    #define REP(i, n) FOR (i, 0, (n))
    #define TRACE(x) cout << #x << " = " << x << endl
    #define _ << " _ " <<
    
    typedef long long llint;
    typedef pair<llint, int> pli;
    
    const int INF = 1e9;
    const int MAXNODES = 262144;
    const int offset = 131072;
    
    inline bool subset(llint mask1, llint mask2) {
      return (mask1 & mask2) == mask1;
    }
    
    int n, k, q;
    
    class tournament {
     private:
      struct node {
        int len;
        pli pref[50];
        pli suff[50];
        int ans;
    
        node() { ans = INF; len = 0; }
        node(int t, int v) {
          len = 1;
          pref[0] = suff[0] = pli(1LL<<v, t);
          ans = INF;
        }
      };
    
      node tree[MAXNODES];
    
      void merge(node &t, node &l, node &r) {
        int pref_len, suff_len;
        
        pref_len = 0;
        for (int i = 0; i < l.len; ++i)
          t.pref[pref_len++] = l.pref[i];
        for (int i = 0; i < r.len; ++i)
          if (pref_len == 0 || !subset(r.pref[i].first, t.pref[pref_len-1].first)) {
            t.pref[pref_len] = r.pref[i];
            if (pref_len > 0) t.pref[pref_len].first |= t.pref[pref_len-1].first;
            ++pref_len;
          }
    
        suff_len = 0;
        for (int i = 0; i < r.len; ++i)
          t.suff[suff_len++] = r.suff[i];
        for (int i = 0; i < l.len; ++i)
          if (suff_len == 0 || !subset(l.suff[i].first, t.suff[suff_len-1].first)) {
            t.suff[suff_len] = l.suff[i];
            if (suff_len > 0) t.suff[suff_len].first |= t.suff[suff_len-1].first;
            ++suff_len;
          }
    
        assert(pref_len == suff_len);
        t.len = pref_len;
    
        t.ans = INF;
        int pref_pos = 0;
        for (int suff_pos = l.len-1; suff_pos >= 0; --suff_pos) {
          while (pref_pos < r.len && (l.suff[suff_pos].first | r.pref[pref_pos].first) != (1LL<<k)-1)
            ++pref_pos;
          if (pref_pos < r.len) {
            llint curr_mask = l.suff[suff_pos].first | r.pref[pref_pos].first;
            if (curr_mask == (1LL<<k)-1)
              t.ans = min(t.ans, r.pref[pref_pos].second-l.suff[suff_pos].second+1);
          }
        }
        t.ans = min(t.ans, min(l.ans, r.ans));
      }
    
    
     public:
      tournament() {}
    
      void update(int t, int v) {
        t += offset;
        tree[t] = node(t-offset, v);
        for (t /= 2; t > 0; t /= 2)
          merge(tree[t], tree[2*t], tree[2*t+1]);
      }
    
      int query(void) {
        return tree[1].ans;
      }
      
    };
    
    tournament T;
    
    int main(void) {
        
    #define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
    FO(nekameleoni) 
      scanf("%d%d%d", &n, &k, &q);
    
      REP (i, n) { 
        int v;
        scanf("%d", &v);
        --v;
        T.update(i, v);
      }
    
      REP (i, q) {
        int t;
        scanf("%d", &t);
        if (t == 1) {
          int x, v;
          scanf("%d%d", &x, &v);
          --x; --v;
          T.update(x, v);
        } else {
          int ans = T.query();
          printf("%d
    ", ans == INF ? -1 : ans);
        }
      }
    
      return 0;
    }
  • 相关阅读:
    网络流24题
    可持久化Treap
    后缀平衡树
    bzoj2561-最小生成树
    poj3164-Command Network
    最小树形图
    hdu2121-Ice_cream’s world II
    线性处理逆元
    bzoj3992-序列统计
    JavaScript 类型转换
  • 原文地址:https://www.cnblogs.com/chouti/p/5900878.html
Copyright © 2020-2023  润新知