NOI Online #1 提高组 序列 冒泡排序

P6185 序列

对于操作2连边: 一个连通块中可以任意操作, 只需保证和不变: 可以用并查集将其缩点
然后对于操作1连边: 如果这个图是二分图, 则要求两部分相同; 否则只需保证总和奇偶性相同

点击查看代码

#include <stdio.h>
#include <string.h>
const int N = 1e5 + 5, M = 2e5 + 5;
typedef signed char byte;
typedef long long LL;
int T, n, m, w[N];
int fa[N], p[N], q[N], tot;
int h[N], e[M], nxt[M], idx;
byte vis[N]; LL val[N], sum[3];
void add(int a, int b) {
	e[++ idx] = b, nxt[idx] = h[a], h[a] = idx;
}
int find(int x) {
	if(x == fa[x]) return x;
	return fa[x] = find(fa[x]);
}
bool dfs(int u, int t) {
	sum[vis[u] = t] += val[u]; bool ret = true;
	for(int i = h[u], v; i; i = nxt[i]) {
		if(vis[v = e[i]] == vis[u]) ret = false;
		if(!vis[v] && !dfs(v, 3 - t)) ret = false;
	}
	return ret;
}
bool solve() {
	scanf("%d%d", &n, &m), tot = idx = 0;
	for(int i = 1; i <= n; i ++) scanf("%d", w + i), fa[i] = i, val[i] = 0;
	for(int i = 1, x; i <= n; i ++) scanf("%d", &x), w[i] -= x;
	for(int i = 1, t, a, b; i <= m; i ++) {
		scanf("%d%d%d", &t, &a, &b);
		if(t == 2) fa[find(a)] = find(b);
		else p[++ tot] = a, q[tot] = b;
	}
	for(int i = 1; i <= n; i ++) val[find(i)] += w[i], h[i] = vis[i] = 0;
	for(int i = 1; i <= tot; i ++) {
		int x = find(p[i]), y = find(q[i]);
		add(x, y), add(y, x);
	}
	for(int i = 1; i <= n; i ++)
		if(i == find(i) && !vis[i]) {
			sum[1] = sum[2] = 0;
			if(dfs(i, 1)) { if(sum[1] != sum[2]) return false; }
			else { if((sum[1] + sum[2]) & 1) return false; }
		}
	return true;
}
int main() {
	scanf("%d", &T);
	while(T --) puts(solve() ? "YES" : "NO");
	return 0;
}

P6186 冒泡排序

设t[i]为以i结尾的逆序对个数
每一次排序后t[i]<-max(t[i+1],0) 即左移,减一,找零
t[1]=0:前移不会减少逆序对
答案为∑max(cnt[i]-x,0)

点击查看代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = 2e5 + 5;
typedef long long LL;
int n, m, a[N], t[N];
int tr1[N]; LL tr2[N]; // tr1为个数,tr2为加权和
inline void add(int x, int cnt, int sum)
{ for(; x; x -= x & -x) tr1[x] += cnt, tr2[x] += sum; }
inline void ask(int x, int &cnt, LL &sum)
{ for(cnt = sum = 0; x <= n; x += x & -x) cnt += tr1[x], sum += tr2[x]; }
int main() {
	scanf("%d%d", &n, &m); int cnt; LL sum;
	for(int i = 1; i <= n; i ++) scanf("%d", a + i);
	for(int i = 1; i <= n; i ++) ask(a[i], t[i], sum), add(a[i], 1, 0);
	memset(tr1 + 1, 0, n << 2);
	for(int i = 1; i <= n; i ++) add(t[i], 1, t[i]);
	for(int i = 0, op, x; i < m; i ++) {
		scanf("%d%d", &op, &x);
		if(op == 1) {
			if(a[x] < a[x + 1]) add(t[x], -1, -t[x]), t[x] ++, add(t[x], 1, t[x]);
			else add(t[x + 1], -1, -t[x + 1]), t[x + 1] --, add(t[x + 1], 1, t[x + 1]);
			std::swap(a[x], a[x + 1]), std::swap(t[x], t[x + 1]);
		} else {
			if(x >= n) puts("0");
			else ask(std::max(1, x), cnt, sum), printf("%lld\n", sum - LL(cnt) * x);
		}
	}
	return 0;
}
posted @ 2022-10-11 11:42  azzc  阅读(27)  评论(0编辑  收藏  举报