[区间计数(元素去重个数)] 树状数组(不变序列) 牛客练习赛47 | DongDong数颜色 HDU-3333 CF-703D

牛客练习赛47 | DongDong数颜色



HH的项链 进阶版
这里对一个子树包含的所有节点进行处理
我们考虑先dfs建序处理成区间问题
然后 跟HH项链一样 我们离线处理
优先处理右区间在前的 不断更新 每个颜色下表位置 从而在权值线段树上统计个数
虽然这里是树状数组写的
(当然数据可能水了 如果是一个链的话 dfs 3e4 差不多就炸栈了 当然也可能是牛客栈区大)

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 5;

int n, m;
int head[maxn], cnt;
int nxt[maxn << 1], to[maxn << 1];

void ade(int a, int b) {
    to[++cnt] = b;
    nxt[cnt] = head[a];
    head[a] = cnt;
}

int in[maxn], out[maxn], tot, pos[maxn];

void dfs(int x, int pre) {
    in[x] = ++tot;
    pos[tot] = x;
    for(int i = head[x]; i; i = nxt[i]) {
        if(to[i] == pre)
            continue;
        dfs(to[i], x);
    }
    out[x] = tot;
}

int col[maxn], vis[maxn], ans[maxn];

struct node {
    int l, r, id;
    bool operator < (const node & a) const {
        return r < a.r;
    }
} que[maxn];

int c[maxn];

void add(int p, int x) {
    for(; p <= n; p += p & -p)
        c[p] += x;
}

int getsum(int p) {
    int ret = 0;
    for(; p; p -= p & -p)
        ret += c[p];
    return ret;
}

int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; ++i)
        cin >> col[i];

    for(int i = 2, x, y; i <= n; ++i) {
        cin >> x >> y;
        ade(x, y), ade(y, x);
    }
    dfs(1, -1);
    for(int i = 1, x; i <= m; ++i) {
        cin >> x;
        que[i] = node {in[x], out[x], i};
    }
    sort(que + 1, que + 1 + m);

    for(int i = 1, p = 1; i <= m; ++i) {
        while(que[i].r >= p && p <= n) {
            int x = col[pos[p]];
            if(vis[x]) {
                add(vis[x], -1);
            }
            add(p, 1);
            vis[x] = p;
            p++;
        }
        ans[que[i].id] = getsum(que[i].r) - getsum(que[i].l - 1);
    }
    for(int i = 1; i <= m; ++i) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

HDU 3333
http://acm.hdu.edu.cn/showproblem.php?pid=3333

统计区间不同数据的和
只要把 -1 +1操作 改成 -a[i] +a[i] 。。。。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;

int n, m;

ll c[maxn], a[maxn], ans[maxn];
map<int, int> vis;

int lowbit(int x) {
	return x & (-x);
}

void add(int x, int y) {
	for(; x <= n; x += lowbit(x))
		c[x] += y;
}

ll getsum(int x) {
	ll res = 0;
	for(; x; x -= lowbit(x))
		res += c[x];
	return res;
}

struct node {
	int l, r, id;
	bool operator < (const node &a) const {
		return r < a.r;
	}
} que[maxn];

int main() {
	int cas ;
	cin >> cas;
	while(cas --) {
		cin >> n ;
		vis.clear();
		memset(c, 0, sizeof c);
		for(int i = 1; i <= n; i ++)
			cin >> a[i];

		cin >> m;
		for(int i = 1, l, r; i <= m; i ++) {
			cin >> l >> r;
			que[i] = node {l, r, i};
		}

		sort(que + 1, que + 1 + m);

		for(int i = 1, p = 1; i <= m; i ++) {
			while(que[i].r >= p) {
				if(vis[a[p]]) {
					add(vis[a[p]], -a[p]);
					vis[a[p]] = p;
				}
				add(p, a[p]);
				vis[a[p]] = p;
				p ++;
			}
			ans[que[i].id] = getsum(que[i].r) - getsum(que[i].l - 1);
		}

		for(int i = 1; i <= m; i ++) {
			cout << ans[i] << endl;
		}
	}
	return 0;
}

Mishka and Interesting sum CodeForces - 703D
统计区间出现偶数次的异或和
这道题 我们如果先搞一个 前缀异或和 是不是处理出了 所有技术次数据的异或值

那么我们考虑 类比上面的 我们可以统计 区间不同(只要一个)数据的异或和 那样 又一个奇数次 异或值被我们处理出来
2次奇数次异或 只会剩下 第二次的数据 这就是偶数次(第一次统计不出来的)数据
将2次异或和进行处理 我们就可以把偶数次的处理出来

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;

int n, m;

int c[maxn], a[maxn], sum[maxn], ans[maxn];
unordered_map<int, int> vis;

int lowbit(int x) {
	return x & (-x);
}

void add(int x, int y) {
	for(; x <= n; x += lowbit(x))
		c[x] ^= y;
}

int getsum(int x) {
	int res = 0;
	for(; x; x -= lowbit(x))
		res ^= c[x];
	return res;
}

struct node {
	int l, r, id;
	bool operator < (node const & a) const {
		return r < a.r;
	}
} que[maxn];

int main() {
// ios::sync_with_stdio(false);cin.tie(0);
	scanf("%d",&n); 
	for(int i = 1; i <= n; i ++)
		scanf("%d",&a[i]), sum[i] = sum[i - 1] ^ a[i];

	cin >> m;
	for(int i = 1, l, r; i <= m; i ++) {
		scanf("%d %d",&l,&r);
		que[i] = node {l, r, i};
	}

	sort(que + 1, que + 1 + m);

	for(int i = 1, p = 1; i <= m; i ++) {
		while(p <= n && que[i].r >= p) {
			if(vis[a[p]]) {
				add(vis[a[p]], a[p]);
				vis[a[p]] = p;
			}
			add(p, a[p]);
			vis[a[p]] = p;
			p ++ ;
		}
		ans[que[i].id] = getsum(que[i].r) ^ getsum(que[i].l - 1) ^ (sum[que[i].r] ^ sum[que[i].l - 1]);
	}

	for(int i = 1; i <= m; i ++) {
		printf("%d\n",ans[i]);
	}
	return 0;
}
全部评论

相关推荐

在评审的大师兄很完美:像这种一般就是部门不匹配 转移至其他部门然后挂掉 我就是这样被挂了
点赞 评论 收藏
分享
我也曾抱有希望:说的好直白
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务