• 【BZOJ 3166】【HEOI 2013】Alo


    http://www.lydsy.com/JudgeOnline/problem.php?id=3166
    这道题难点在于求能对一个次大值有贡献的区间。
    设这个次大值为(a_i)(a_i)左边第一个和第二个比它大的设为(l_1)(l_2),右边第一个和第二个比它大的设为(r_1)(r_2)
    (a_i)是次大值的区间就是((l_1,r_2))((l_2,r_1))(直接排序后用set就可以了)。
    找这两个区间里和(a_i)的异或最大值(实际上可以求两个区间的并),直接用主席树就可以了(为什么叫它可持久化Trie?什么是可持久化Trie?)
    空间开小了导致WA,以后主席树不能再卡着空间开了qwq
    时间复杂度(O(nlog n))

    #include<set>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 50003;
    int l1[N], l2[N], r1[N], r2[N], a[N], id[N], n;
    set <int> s;
    set <int> :: iterator it, itl, itr;
    
    bool cmp(int x, int y) {return a[x] < a[y];}
    
    struct node {
    	int l, r, s;
    } T[N * 31];
    int root[N], cnt = 0;
    
    int cc;
    
    void update(int &pos, int tmp, int num) {
    	T[++cnt] = T[pos]; pos = cnt; ++T[pos].s;
    	if (tmp == -1) return;
    	if ((1 << tmp) & num) update(T[pos].r, tmp - 1, num);
    	else update(T[pos].l, tmp - 1, num);
    }
    
    int ask(int Tl, int Tr, int tmp, int num) {
    	if (tmp == -1) return 0;
    	if ((1 << tmp) & num) {
    		if (T[T[Tr].l].s - T[T[Tl].l].s == 0) return ask(T[Tl].r, T[Tr].r, tmp - 1, num);
    		else return (1 << tmp) | ask(T[Tl].l, T[Tr].l, tmp - 1, num);
    	} else {
    		if (T[T[Tr].r].s - T[T[Tl].r].s == 0) return ask(T[Tl].l, T[Tr].l, tmp - 1, num);
    		else return (1 << tmp) | ask(T[Tl].r, T[Tr].r, tmp - 1, num);
    	}
    }
    
    int main() {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; ++i) scanf("%d", a + i), id[i] = i;
    	stable_sort(id + 1, id + n + 1, cmp);
    	for (int i = n; i >= 1; --i) {
    		s.insert(id[i]);
    		it = s.lower_bound(id[i]);
    		itl = itr = it;
    		if (itl != s.begin())
    			--itl, l1[id[i]] = *itl;
    		if (itl != s.begin())
    			--itl, l2[id[i]] = *itl;
    		if (itr != --s.end())
    			++itr, r1[id[i]] = *itr;
    		else r1[id[i]] = n + 1;
    		if (itr != --s.end())
    			++itr, r2[id[i]] = *itr;
    		else r2[id[i]] = n + 1;
    	}
    	
    	for (int i = 1; i <= n; ++i) {
    		root[i] = root[i - 1];
    		update(root[i], 29, a[i]);
    	}
    	
    	int ans = 0;
    	for (int i = 1; i <= n; ++i)
    		if (l1[i] != 0 || r1[i] != n + 1)
    			ans = max(ans, ask(root[l2[i]], root[r2[i] - 1], 29, a[i]));
    	
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    转载c++中的多态性
    sdk环境下数据库访问之ADO
    ADO数据库访问问题
    PopMenu 弹出式菜单(变灰,禁用,激活)
    控制台窗口界面控制设计
    判断整数序列是不是二元查找树的后序遍历结果
    把二元查找树转变成排序的双向链表
    二叉树平衡因子应用举例
    二元查找树转换为它的镜像
    满二叉树先序、中序和后序之间的转换
  • 原文地址:https://www.cnblogs.com/abclzr/p/6308903.html
Copyright © 2020-2023  润新知