• [CTSC2008]网络管理 动态主席树


    题面

    直接去洛谷看吧

    题解

    首先这是一道树上区间第k大的问题, 他求的是第k小, 转换一下就行

    1、树剖+线段树套平衡树,查询时需要二分答案, 代码200行就出去了, 还是4个logn卡过去的

    2、树剖+动态主席树(或者Kruskal重构树?),省去了2分, 3logn, 代码也是200+

    3、作为个懒狗, 菜鸡这种200+的实在不友好, 复杂度也不友好

    不管结构的话, 就是一个 动态第k大, 动态主席树秒了

    然而这是颗树, 就有了树剖的logn

    树剖有的dfs序是很巧妙的, 子树的序号是连续的

    每次修改只影响子树, 而子树的编号又是连续的~

    那我们就可以修改的时候是个区间修改!(当然先跑出来dfs序)

    正好动态主席树就是树状(线段树维护的), 支持区间修改!

    剩下的迎刃而解

    什么你不知道怎么树上算值域个数?

    在值域[l, r], (s, t)上的个数为, (root, s) + (root, t) - (root, lca(s, t)) - (root, father[lca(s, t)]);

    2个优美的log, 收工

    代码

    #include <bits/stdc++.h>
    #define all(n) (n).begin(), (n).end()
    #define se second
    #define fi first
    #define pb push_back
    #define mp make_pair
    #define sqr(n) (n) * (n)
    #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
    #define per(i, a, b) for (int i = (a); i >= (b); --i)
    #define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    typedef vector<int> VI;
    typedef double db;
    
    template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
    template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
    template<class T> void clear(T& a) { T().swap(a); }
    
    const int N = 8e4 + 5;
    
    struct STFrom {
    	static const int N = 8e4 + 5;
    	
    	int f[N][20], dep[N], t;
    	int *h, *ne, *to;
    
    	void init(int n, int* H, int* Ne, int* To) {
    		t = log2(n - 1) + 1;
    		h = H, ne = Ne, to = To;
    	}
    
    	void bfs(int s) {
    		queue<int> q;
    		q.push(s); dep[s] = 1;
    		rep (i, 0, t) f[s][i] = 0;
    
    		while (!q.empty()) {
    			int x = q.front(); q.pop();
    			for (int i = h[x]; i; i = ne[i]) {
    				int y = to[i];
    				if (dep[y]) continue;
    				dep[y] = dep[x] + 1;
    				f[y][0] = x;
    
    				for (int j = 1; j <= t; ++j)
    					f[y][j] = f[f[y][j - 1]][j - 1];
    				q.push(y);
    			}
    		}
    	}
    
    	int lca(int x, int y) {
    		if (dep[x] > dep[y]) swap(x, y);
    		per (i, t, 0) if (dep[f[y][i]] >= dep[x]) y = f[y][i];
    		if (x == y) return x;
    		per (i, t, 0) 
    			if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    		return f[x][0];
    	}
    
    	int dist(int x, int y) {
    		return dep[x] + dep[y] - (dep[lca(x, y)] << 1);
    	}
    } ST;
    
    struct CHT {
        static const int M = 6e7;
    
        struct node {
            int val, lson, rson; /*int l, r; 值域*/
            node (int Val = 0, int Ls = 0, int Rs = 0)
                : val(Val), lson(Ls), rson(Rs){}
        } tr[N * 520]; //log2(sz)*log2(sz)*n
    
        int root[N], tot, qsc, qtc, quc, qwc, sz, n; // n为数组大小,sc为值域
        int qs[15], qt[15], qu[15], qw[15]; //log(n)
    
        void build(int n, int sz, int *a, PII *dfn) {
            this->sz = sz; this->n = n;
            for (int i = 1; i <= n; ++i)
                change(dfn[i].fi, a[i], 1), change(dfn[i].se + 1, a[i], -1);
        }
    
        void update(int &rt, int l, int r, int k, int cnt) {
            if (!rt) rt = ++tot;
            tr[rt].val += cnt;
            if (l == r) return;
            int mid = l + r >> 1;
            if (k <= mid) update(tr[rt].lson, l, mid, k, cnt);
            else update(tr[rt].rson, mid + 1, r, k, cnt);
        }
    
        void change(int x, int k, int cnt) { //n为最大区间长度
            for (int i = x; i <= n; i += i & -i)
                update(root[i], 0, sz, k, cnt);
        }
    
        int ask(int l, int r, int k) {
            if (l == r) return l;
            int sum = 0;
            for (int i = 1; i <= qsc; ++i) sum += tr[tr[qs[i]].lson].val;
            for (int i = 1; i <= qtc; ++i) sum += tr[tr[qt[i]].lson].val;
            for (int i = 1; i <= quc; ++i) sum -= tr[tr[qu[i]].lson].val;
            for (int i = 1; i <= qwc; ++i) sum -= tr[tr[qw[i]].lson].val;
            int mid = l + r >> 1;
            if (sum >= k) {
                for (int i = 1; i <= qsc; ++i) qs[i] = tr[qs[i]].lson;
                for (int i = 1; i <= qtc; ++i) qt[i] = tr[qt[i]].lson;
                for (int i = 1; i <= quc; ++i) qu[i] = tr[qu[i]].lson;
                for (int i = 1; i <= qwc; ++i) qw[i] = tr[qw[i]].lson;
                return ask(l, mid, k);
            } else {
                for (int i = 1; i <= qsc; ++i) qs[i] = tr[qs[i]].rson;
                for (int i = 1; i <= qtc; ++i) qt[i] = tr[qt[i]].rson;
                for (int i = 1; i <= quc; ++i) qu[i] = tr[qu[i]].rson;
                for (int i = 1; i <= qwc; ++i) qw[i] = tr[qw[i]].rson;
                return ask(mid + 1, r, k - sum);
            }
        }
    
        int preask(int s, int t, int u, int w, int k) {
            qtc = qsc = quc = qwc = 0;
            for (int i = s; i; i -= -i & i) qs[++qsc] = root[i];
            for (int i = t; i; i -= -i & i) qt[++qtc] = root[i];
            for (int i = u; i; i -= -i & i) qu[++quc] = root[i];
            for (int i = w; i; i -= -i & i) qw[++qwc] = root[i];
            return ask(0, sz, k);
        }
    } bit;
    
    int n, m, _, k;
    int h[N], ne[N << 1], to[N << 1], tot;
    int op[N], x[N], y[N];
    int a[N], df;
    PII dfn[N];
    
    void add(int u, int v) {
        ne[++tot] = h[u]; to[h[u] = tot] = v;
    }
    
    void dfs(int x, int f) {
        dfn[x].fi = ++df;
        for (int i = h[x]; i; i = ne[i]) {
            int y = to[i];
            if (y == f) continue;
            dfs(y, x);
        }
        dfn[x].se = df;
    }
    
    int main() {
        IOS; cin >> n >> m; VI c;
        rep (i, 1, n) cin >> a[i], c.pb(a[i]);
        rep (i, 2, n) {
            int u, v; cin >> u >> v;
            add(u, v); add(v, u);
        }
    
        rep (i, 1, m) {
            cin >> op[i] >> x[i] >> y[i];
            if (!op[i]) c.pb(y[i]);
        }
        sort(all(c)); c.erase(unique(all(c)), c.end());
        rep (i, 1, n) a[i] = lower_bound(all(c), a[i]) - c.begin();
        rep (i, 1, m) if (!op[i]) y[i] = lower_bound(all(c), y[i]) - c.begin(); 
    
        ST.init(n, h, ne, to); ST.bfs(1);
        dfs(1, 0); bit.build(n, c.size(), a, dfn);
        rep (i, 1, m) {
            if (!op[i]) {
                bit.change(dfn[x[i]].fi, a[x[i]], -1);
                bit.change(dfn[x[i]].se + 1, a[x[i]], 1);
                a[x[i]] = y[i];
                bit.change(dfn[x[i]].fi, a[x[i]], 1);
                bit.change(dfn[x[i]].se + 1, a[x[i]], -1);
            } else {
                int k = ST.dist(x[i], y[i]) + 2 - op[i], lca = ST.lca(x[i], y[i]);
                if (k <= 0) cout << "invalid request!
    ";
                else cout << c[bit.preask(dfn[x[i]].fi, dfn[y[i]].fi,
                    dfn[lca].fi, dfn[ST.f[lca][0]].fi, k)] << '
    ';
            }
        }
        return 0;
    }
    
  • 相关阅读:
    S2 第二章数据库的实现
    理解ThreadLocal(之二)
    理解ThreadLocal(之一)
    save(),saveOrUpdate(),merge()的区别
    Hibdernate入门
    Hibernate第一个例子
    在运行Hibernate Hello World程序的时候,抛如下错误: view plain Exception in thread "main" org.hibernate.exception.LockAcquisitionException 解决方法
    Oracle函数
    UDP
    多线程下真正的单例
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/13995982.html
Copyright © 2020-2023  润新知