zoukankan      html  css  js  c++  java
  • JZOJ 5753. 完全二叉树 (可持久化线段树维护hash值)

    https://gmoj.net/senior/#main/show/5753

    (1le n le 1e5)

    题解:

    加入一个串之后答案会发生什么变化呢?

    (ans+=n-max{lcp(news,s'in oldS)})

    现在思考如何快速求两个串的lcp,发现可以维护每个串的hash值的线段树,然后在上面二分即可。

    由势能分析,每次加法后的发生改变的位的个数和是(O(Q))的,因此每次发生的改变可以暴力在线段树上修改。

    但现在要查询的是lcp的最大值,如果把所有串排序,那lcp最大值肯定是在(news)的前一个或后一个和(news)的lcp。

    考虑用平衡树动态维护串排好序的结果,比较时在线段树上查询即可,时间复杂度:(O(n*log^2~n))

    平衡树是不必要的,重载之后用multiset即可。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const ll mo = 23333333333333333;
    
    ll mul(ll x, ll y) {
    	ll z = (long double) x * y / mo;
    	z = x * y - z * mo;
    	if(z < 0) z += mo; else if(z >= mo) z -= mo;
    	return z;
    }
    
    const int N = 1e5 + 5;
    
    int n, q, op, x;
    
    int a[N];
    
    ll a2[N];
    
    #define i0 t[i].l
    #define i1 t[i].r
    struct tree {
    	int l, r; ll s;
    } t[N * 40]; int tt;
    
    int rt[N];
    
    void bt(int &i, int x, int y) {
    	i = ++ tt;
    	if(x == y) return;
    	int m = x + y >> 1;
    	bt(i0, x, m); bt(i1, m + 1, y);
    }
    
    int pl, pr, px;
    
    void add(int &i, int x, int y) {
    	if(y < pl || x > pr) return;
    	t[++ tt] = t[i], i = tt;
    	if(x == y) {
    		t[i].s = a[n - x + 1];
    		return;
    	}
    	int m = x + y >> 1;
    	add(i0, x, m); add(i1, m + 1, y);
    	t[i].s = (t[i0].s + mul(a2[m - x + 1], t[i1].s)) % mo;
    }
    
    void ef(int i, int j, int x, int y) {
    	if(t[i].s == t[j].s) { px = y; return;}
    	if(x == y) return;
    	int m = x + y >> 1;
    	ef(t[i].l, t[j].l, x, m);
    	if(px == m) ef(t[i].r, t[j].r, m + 1, y);
    }
    
    int val(int i, int x, int y, int l) {
    	if(x == y) return t[i].s;
    	int m = x + y >> 1;
    	return l <= m ? val(i0, x, m, l) : val(i1, m + 1, y, l);
    }
    
    int lcp(int i, int j) {
    	px = 0;
    	ef(rt[i], rt[j], 1, n);
    	return px;
    }
    
    int cmp(int i, int j) {
    	int z = lcp(i, j);
    	if(z == n) return 0;
    	return val(rt[i], 1, n, z + 1) < val(rt[j], 1, n, z + 1);
    }
    
    struct P {
    	int x;
    	P(int _x = 0) { x = _x;}
    };
    
    bool operator < (P a, P b) {
    	return cmp(a.x, b.x);
    }
    
    void pcj(int &rt, int x) {
    	a[x] ++;
    	int y = x;
    	while(y <= n && a[y] > 1) {
    		a[y] %= 2, a[y + 1] ++;
    		y ++;
    	}
    	if(y > n) y = n;
    	pl = n - y + 1, pr = n - x + 1;
    	add(rt, 1, n);
    }
    
    multiset<P> s;
    
    ll ans;
    
    void ins(P a) {
    	if(s.empty()) {
    		s.insert(a);
    		ans += n;
    		return;
    	}
    	int mx = 0;
    	P b = (*--s.end()) ;
    	if(!(b < a)) {
    		b = *s.lower_bound(a);
    		mx = max(mx, lcp(a.x, b.x));
    	}
    	b = *s.begin();
    	if(b < a) {
    		b = (*--s.lower_bound(a));
    		mx = max(mx, lcp(a.x, b.x));
    	}
    	ans += n - mx;
    	s.insert(a);
    }
    
    int main() {
    	freopen("tree.in", "r", stdin);
    	freopen("tree.out", "w", stdout);
    	a2[0] = 1; fo(i, 1, 1e5) a2[i] = a2[i - 1] * 2 % mo;
    	scanf("%d %d", &n, &q);
    	bt(rt[0], 1, n);
    	ans = 1;
    	fo(i, 1, q) {
    		scanf("%d", &op);
    		rt[i] = rt[i - 1];
    		if(op == 1) {
    			scanf("%d", &x); x ++;
    			pcj(rt[i], x);
    			ins(P(i));
    		} else {
    			pp("%lld
    ", ans);
    		}
    	}
    }
    
  • 相关阅读:
    IDS与IPS功能分析
    CentOS 命令大全
    仿京东放大镜
    CSS垂直水平居中方法总结
    Java学习之计算机基础(一)
    Java 代码学习之理解数据类型中的坑
    Java 代码学习之数组的初始化
    Java中的比较总结
    Java Random介绍
    手机网站开发必修课[2]:浏览器兼容性测试
  • 原文地址:https://www.cnblogs.com/coldchair/p/12857774.html
Copyright © 2011-2022 走看看