• luogu3380 树套树之线段树套线段树


    个人感觉可能是最不需要脑子写的方法

    不过也不太好调

    就是用一个普通的线段树维护这个序列,但是对于线段树的每一个区间,再开一个动态开点的权值线段树,里面存储这个区间所有元素值

    单点修改只会涉及到log棵权值线段树的单点修改(不用打lazy太棒了 log^2

    查询区间内x的排名相当于查询区间内<x的数的个数+1,我们把区间分成log个外层线段树上的区间,然后在每个权值线段树上统计即可,复杂度log^2

    查询排名为x的数比较麻烦,我们直接二分,复杂度log^3

    查询前驱后继:由于线段树维护的区间,总区间是把这log个区间相加,所以我们再每个权值线段树查询下前驱后继再合并就行,前驱取max,后继取min

    至于怎么查询,可以在线段树上二分

    代码写的特别乱...

    #include <cstdio>
    #include <functional>
    using namespace std;
    
    
    
    int l[17000010], r[17000010], tree[17000010], tot;
    int rt[200010], init[50010], fuck = 100000000;
    int s[10000010], top;
    
    int n, m;
    
    void chenge(int &x, int cl, int cr, int pos, int val)
    {
    	if (x == 0)
    	{
    		if (top > 0) x = s[top--];
    		else x = ++tot;
    	}
    	if (tot % 100000 == 0) fprintf(stderr, "(%d, %d)
    ", tot, top);
    	if (cl == cr) {tree[x] += val; if (tree[x] == 0) s[++top] = x, x = 0; return; }
    	int mid = (cl + cr) / 2;
    	if (pos > mid) chenge(r[x], mid + 1, cr, pos, val);
    	else chenge(l[x], cl, mid, pos, val);
    	tree[x] = tree[l[x]] + tree[r[x]];
    	if (l[x] == 0 && r[x] == 0) { s[++top] = x, x = 0; }
    }
    
    int query(int x, int cl, int cr, int pos)
    {
    	if (x == 0 || cl == cr) return 0;
    	int mid = (cl + cr) / 2;
    	if (pos > mid)
    		return tree[l[x]] + query(r[x], mid + 1, cr, pos);
    	else return query(l[x], cl, mid, pos);
    }
    
    int qrange(int x, int cl, int cr, int L, int R)
    {
    	if (x == 0) return 0;
    	if (R < cl || cr < L) return 0;
    	if (L <= cl && cr <= R) return tree[x];
    	int mid = (cl + cr) / 2;
    	return qrange(l[x], cl, mid, L, R) + qrange(r[x], mid + 1, cr, L, R);
    }
    
    int getnumber(int x, int cl, int cr, int rank)
    {
    	if (cl == cr) { return cl; }
    	int mid = (cl + cr) / 2;
    	if (rank <= tree[l[x]]) return getnumber(l[x], cl, mid, rank);
    	else return getnumber(r[x], mid + 1, cr, rank - tree[l[x]]);
    }
    
    int getnumber2(int x, int cl, int cr, int rank)
    {
    	if (cl == cr) { return cl; }
    	int mid = (cl + cr) / 2;
    	if (rank <= tree[r[x]]) return getnumber2(r[x], mid + 1, cr, rank);
    	else return getnumber2(l[x], cl, mid, rank - tree[r[x]]);
    }
    
    int getprev(int rt, int pos)
    {
    	int tot = qrange(rt, 0, fuck, 0, pos - 1); // [1, pos - 1]内数的个数
    	if (tot == 0) return -2147483647;
    	return getnumber(rt, 0, fuck, tot);
    }
    
    int getnext(int rt, int pos)
    {
    	int tot = qrange(rt, 0, fuck, pos + 1, fuck);
    	if (tot == 0) return 2147483647;
    	return getnumber2(rt, 0, fuck, tot);
    }
    
    //---- 外面线段树
    
    void build(int x, int l, int r)
    {
    	for (int i = l; i <= r; i++)
    		chenge(rt[x], 0, fuck, init[i], 1);
    	if (l == r) return;
    	int mid = (l + r) / 2;
    	build(x * 2, l, mid);
    	build(x * 2 + 1, mid + 1, r);
    }
    
    int qrank(int x, int cl, int cr, int L, int R, int k)
    {
    	if (R < cl || cr < L) return 0;
    	if (L <= cl && cr <= R) return query(rt[x], 0, fuck, k);
    	int mid = (cl + cr) / 2;
    	return qrank(x * 2, cl, mid, L, R, k) + qrank(x * 2 + 1, mid + 1, cr, L, R, k);
    }
    
    void change(int x, int cl, int cr, int pos, int val)
    {
    	chenge(rt[x], 0, fuck, init[pos], -1);
    	chenge(rt[x], 0, fuck, val, 1);
    	if (cl == cr) return;
    	int mid = (cl + cr) / 2;
    	if (pos > mid) change(x * 2 + 1, mid + 1, cr, pos, val);
    	else change(x * 2, cl, mid, pos, val);
    }
    
    int qprev(int x, int cl, int cr, int L, int R, int k)
    {
    	if (R < cl || cr < L) return -2147483647;
    	if (L <= cl && cr <= R)
    	{
    		int res = getprev(rt[x], k);
    		return res;
    	}
    	int mid = (cl + cr) / 2;
    	return max(qprev(x * 2, cl, mid, L, R, k), qprev(x * 2 + 1, mid + 1, cr, L, R, k));
    }
    
    int qnext(int x, int cl, int cr, int L, int R, int k)
    {
    	if (R < cl || cr < L) return 2147483647;
    	if (L <= cl && cr <= R) return getnext(rt[x], k);
    	int mid = (cl + cr) / 2;
    	return min(qnext(x * 2, cl, mid, L, R, k), qnext(x * 2 + 1, mid + 1, cr, L, R, k));
    }
    
    int main()
    {
    	// printf("%f
    ", (3 * sizeof(l) + sizeof(s) + sizeof(rt)) / 1000000.);
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; i++)
    		scanf("%d", &init[i]);
    	build(1, 1, n);
    	for (int opd, l, r, k, i = 1; i <= m; i++)
    	{
    		scanf("%d%d%d", &opd, &l, &r);
    		if (opd != 3) scanf("%d", &k);
    		if (opd == 1)
    		{
    			printf("%d
    ", qrank(1, 1, n, l, r, k) + 1);
    		}
    		if (opd == 2) // query值<k的最大一撮数中最小的一个
    		{
    			// for (int i = 0; i <= 10; i++) printf("query(%d) = %d
    ", i, qrank(1, 1, n, l, r, i));
    			int cl = 0, cr = 100000000;
    			while (cl < cr)
    			{
    				int mid = (cl + cr + 1) / 2;
    				if (qrank(1, 1, n, l, r, mid) < k) cl = mid;
    				else cr = mid - 1;
    			}
    			// int ans = qrank(1, 1, n, l, r, cl);
    			// cl = 0, cr = 100000000;
    			// while (cl < cr)
    			// {
    				// int mid = (cl + cr) / 2;
    				// if (qrank(1, 1, n, l, r, mid) >= ans) cr = mid;
    				// else cl = mid + 1;
    			// }
    			printf("%d
    ", cl);
    		}
    		if (opd == 3)
    		{
    			change(1, 1, n, l, r);
    			init[l] = r;
    		}
    		if (opd == 4)
    		{
    			printf("%d
    ", qprev(1, 1, n, l, r, k));
    		}
    		if (opd == 5)
    		{
    			printf("%d
    ", qnext(1, 1, n, l, r, k));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    扩展欧几里得算法
    poj-3094-quicksum
    (floyd)佛洛伊德算法
    poj-3660-cows contest(不懂待定)
    poj-1056-IMMEDIATE DECODABILITY(字典)
    delete与delete[]的区别
    poj-1046-color me less
    SqlParameter 使用
    VS2010中出现无法嵌入互操作类型(转)
    fastreport代码转
  • 原文地址:https://www.cnblogs.com/oier/p/10350446.html
Copyright © 2020-2023  润新知