• 可持久化线段树


    特点

    老师说,可持久化线段树一个重要的特点就是,它的询问都是单点询问...
    先记这....等我做多了题目之后再补充

    李超线段树

    用于维护若干个一次函数的最值

    核心思想就是标记永久化, 线段树每个节点维护在该区间中点取值最大的线段,查询时求一条从上到下的链上log个线段的最值。
    ————一位大佬FlashHu

    例题

    luoguP4097 [HEOI2013]Segment

    思路: 一个区间只有在绝对不可能是答案的时候才更新,否则就把原来的/插入的的区间往下递归,插入的/原来的区间就放在当前区间,这样,我们只要把合适的区间往下递归,合适的区间留下,那么对于当前区间,无论是左边还是右边,我们都能求出最优解

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAX = 40000;
    
    int n, lastans, cnt;
    
    struct line{
    	double k, b;
    	int id;
    	line()  {}
    	line(int x1, int y1, int x2, int y2, int cnt) : id(cnt) {
    		if(x1 == x2) k = 0, b = max(y1, y2);
    		else k = (double)(y2-y1)/(x2-x1), b = (double)y1-k*x1;
    	}
    	double calc(int x) {
    		return k*x+b;
    	}
    }tr[MAX<<2];
    
    bool cmp(line a, line b, int x) {//在点x处b高于a || 高度相等且b的id比a小 ->返回1 
    	double tmp1 = a.calc(x), tmp2 = b.calc(x);
    	return tmp1 != tmp2 ? tmp1 < tmp2 : a.id > b.id;
    }
    line query(int o, int l, int r, int x) {//因为是要返回id,而不是高度,所以返回类型设为line好一些 
    	if(l == r) return tr[o];
    	int mid = (l+r)>>1;
    	line tmp;
    	if(x <= mid) tmp = query(o<<1, l, mid, x);
    	else tmp = query(o<<1|1, mid+1, r, x);
    	return cmp(tr[o], tmp, x) ? tmp : tr[o];
    }
    void solve(int o, int l, int r, line x) { //建议手画
    	if(!tr[o].id) {tr[o] = x; return ;}
    	if(cmp(tr[o], x, l)) swap(tr[o], x);//目前tr[o]里保存的是左端点高的
    	if(l == r || tr[o].k == x.k) return ;//是叶子节点 或 是两条平行直线 的情况上一行考虑过了 
    	int mid = (l+r)>>1;
    	double delta = (tr[o].b-x.b)/(x.k-tr[o].k);//计算交点
    	if(delta < l || delta > r) return ;//交点不在区间内 ->也是在cmp那行考虑过了
    	//我们要下传的,肯定是可能成为答案的,即tr[o]或x 的 [l, delta]或[delta, r],其它部分就不用了 
    	if(delta <= mid) solve(o<<1, l, mid, tr[o]), tr[o] = x;
    	//交点在左区间->tr[o]的delta以左可能是答案,并且我们又要保证整个区间中delta以右的答案不丢,所以tr[o] = x 
    	else solve(o<<1|1, mid+1, r, x);//交点在右区间->x的delta以右可能是答案 
    }
    
    void change(int o, int l, int r, int ql, int qr, line tmp) {
    	 if(ql <= l && r <= qr) {solve(o, l, r, tmp); return ;}
    	 int mid = (l+r)>>1;
    	 if(ql <= mid) change(o<<1, l, mid, ql, qr, tmp);
    	 if(mid < qr) change(o<<1|1, mid+1, r, ql, qr, tmp);
    }
    
    int main() {
    	scanf("%d",&n);
    	int cmd, x1, x2, y1, y2;   
    	for(int i = 1; i <= n; i++) {
    		scanf("%d",&cmd);
    		if(cmd == 1) {
    			scanf("%d%d%d%d",&x1, &y1, &x2, &y2);
    			x1 = (x1+lastans-1)%39989+1, y1 = (y1+lastans-1)%(1000000000)+1;
    			x2 = (x2+lastans-1)%39989+1, y2 = (y2+lastans-1)%(1000000000)+1;
    			if(x1 > x2) swap(x1, x2), swap(y1, y2);
    			change(1, 1, MAX, x1, x2, line(x1, y1, x2, y2, ++cnt));
    		} else {
    			scanf("%d",&x1);
    			x1 = (x1+lastans-1)%39989+1;
    			lastans = query(1, 1, MAX, x1).id;
    			printf("%d
    ", lastans);
    		}
    	}
    }
    
  • 相关阅读:
    C#获取当前路径的七种方法
    map容器对象插入数据的4种方式【转】
    为VMware虚拟机内安装的Ubuntu 16.04设置静态IP地址【转】
    Ubuntu16手动配置IP地址
    当前上下文不存在名称“***”
    C++读写文件ofstream,ifstream,fstream)[转]
    atoi()函数
    C++常用输出 cout、cerr、clog
    Lucene教程(转)
    selenium环境搭建1
  • 原文地址:https://www.cnblogs.com/tyner/p/11785125.html
Copyright © 2020-2023  润新知