zoukankan      html  css  js  c++  java
  • BZOJ1106 [POI2007]立方体大作战tet

    树状数组

    原题链接

    先说一个结(cai)论(xiang),当两个相同的元素之间有(x)个元素是成单的,那么一定要交换(x)次。
    然而我并不会证(举例子算吗)
    然后我们就可以考虑用树状数组来维护两个相同元素之间有多少元素成单。
    我们可以直接一个指针扫过去,当遇到一个第一次出现的元素(x)时,记录他的位置(v[x]=i),并(add(i,1)),即在树状数组上对应的位置进行加(1);当遇到第二次出现的元素时,将这个元素之前出现的位置执行(add(v[x],-2)),即将其在树状数组上变为(-1),再将当前位置(add(i,1))。这时我们会发现,在扫到相同元素时,这两个元素之间的区间和就是成单元素的数量。
    时间复杂度(O(nlogn))
    注意最终结果要除(2),因为对于每对不同元素都计算了两次,所以要除去。

    #include<cstdio>
    using namespace std;
    const int N = 1e5 + 10;
    int C[N], v[N >> 1], n;
    int re()
    {
    	int x = 0;
    	char c = getchar();
    	bool p = 0;
    	for (; c<'0' || c>'9'; c = getchar())
    		p = (c == '-' || p) ? 1 : 0;
    	for (; c >= '0'&&c <= '9'; c = getchar())
    		x = x * 10 + (c - '0');
    	return p ? -x : x;
    }
    inline int lowbit(int x)
    {
    	return x & -x;
    }
    inline void add(int x, int y)
    {
    	for (; x <= n; x += lowbit(x))
    		C[x] += y;
    }
    inline int ask(int x)
    {
    	int s = 0;
    	for (; x; x -= lowbit(x))
    		s += C[x];
    	return s;
    }
    int main()
    {
    	int i, x, s = 0;
    	n = re() << 1;
    	for (i = 1; i <= n; i++)
    	{
    		x = re();
    		if (!v[x])
    			v[x] = i;
    		else
    		{
    			add(v[x], -2);
    			s += ask(i - 1) - ask(v[x]);
    		}
    		add(i, 1);
    	}
    	printf("%d", s >> 1);
    	return 0;
    }
    
  • 相关阅读:
    Day12 文件操作
    Day11 集合、集合操作
    Day10 【小程序】商城管理(购物车小程序的增强版)
    Day8 字符串操作
    Day9 字典操作
    文件操作
    【python练习】购物车程序
    2296 寻找道路
    2661 信息传递(tarjan&拓扑)
    【模板】LCA(tarjan)
  • 原文地址:https://www.cnblogs.com/Iowa-Battleship/p/9535135.html
Copyright © 2011-2022 走看看