列表

详情


NC52938. 树上逆序对

描述

在可能性的系统树上,一共有 n 个事件,正如它们的名字一般,它们形成了一棵树的关系。

现在我们默认1号事件是所有事件的根节点。 不同的事件会产生不同的可能性,为了区分,每一个事件有一个关键值 a_i ,并且保证各不相同。

您拥有 "Rewrite" 的能力,在这棵可能性的系统树上,您可以对任意一个事件进行改写,让它的关键值变成 -a_i 。为了创造新的可能性,你需要让这棵树的树上逆序对数为 k .

来自篝火的指引:树上逆序对的定义:若有一对节点(x,y),满足x是y的祖先,且x点权值大于y点的权值,则(x,y)为一个树上逆序对。

由于需要尽可能多的探索生命的可能,您会进行q次询问。

输入描述

输入的第一行包含一个整数n,表示事件数。

第二行n个正整数,表示每个节点初始的关键值,每个关键值都各不相同。

接下来n-1行,每行两个数x,y表示x,y之间有树边相连。

下面一行q表示询问个数。

接下来q行,每行一个数k表示询问树上逆序对数能否为k。

100%的数据,满足1≤x,y≤n,n,q≤100000,k≤30000,a_i≤100000000

输出描述

对于每次询问,若可以为k输出“Orz”,若不可以输出“QAQ”。

示例1

输入:

5
2 4 5 1 3
1 2
1 3
2 4
2 5
2
3
4

输出:

Orz
Orz

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 320ms, 内存消耗: 8804K, 提交时间: 2019-09-26 23:05:10

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

const int N = 1e5 + 7;

bitset<30001> mask;

int n;

struct BIT {
	int tree[N];
	inline int lowbit(int x) {
		return x & -x;
	}
	void add(int x, int v) {
		if (!x) return;
		for (int i = x; i <= n; i += lowbit(i))
			tree[i] += v;
	}
	int query(int x) {
		int ans = 0;
		for (int i = x; i; i -= lowbit(i)) 
			ans += tree[i];
		return ans;
	}
} bit[2];

int a[N], in[N], out[N], tol, o[N];
vector<int> G[N];

void dfs(int u, int fa) {
	in[u] = ++tol;
	for (auto v: G[u])
		if (v != fa) dfs(v, u);
	out[u] = tol;
}

bool cmp(const int &x, const int &y) {
	return a[x] < a[y];
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		o[i] = i;
	}
	sort(o + 1, o + n + 1, cmp);
	for (int i = 1; i < n; i++) {
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1, -1);
	mask.set(0);
	for (int i = 1; i <= n; i++) {
		int u = o[i];
		int k1 = bit[0].query(in[u]), k2 = bit[1].query(out[u]) - bit[1].query(in[u] - 1);
		mask = mask << k1 | mask << k2;
		bit[0].add(in[u] + 1, 1); bit[0].add(out[u] + 1, -1);
		bit[1].add(in[u], 1);
	}
	int q;
	scanf("%d", &q);
	while (q--) {
		int k;
		scanf("%d", &k);
		puts(mask.test(k) ? "Orz" : "QAQ");
	}
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 341ms, 内存消耗: 14232K, 提交时间: 2019-09-20 21:14:01

#include<cstdio>
#include<algorithm>
#include<vector>
#include<bitset>
using namespace std;

const int N=1e5+5;

int q,n,a[N],o[N],id[N],tim,foo[N],bar[N],bit[N];
vector<int>E[N],Q[N];
bitset<30001>dp;

void modify(int x,int v){
	while(x<=n)bit[x]+=v,x+=x&-x;
}

int query(int x){
	int res=0;
	while(x)res+=bit[x],x^=x&-x;
	return res;
}

void dfs(int u,int f){
	id[++tim]=a[u];
	Q[tim].push_back(-u);
	foo[u]=query(a[u]);modify(a[u],1);
	for(int v:E[u])if(v!=f)dfs(v,u);
	modify(a[u],-1);
	Q[tim].push_back(u);
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]),o[i]=a[i];
	sort(o+1,o+n+1);
	for(int i=1;i<=n;++i)a[i]=lower_bound(o+1,o+n+1,a[i])-o;
	for(int i=1,x,y;i<n;++i){
		scanf("%d%d",&x,&y);
		E[x].push_back(y);E[y].push_back(x);
	}
	dfs(1,0);
	for(int i=1;i<=n;++i){
		modify(id[i],1);
		for(int j:Q[i])
			if(j>0)bar[j]+=query(a[j]);
			else bar[-j]-=query(a[-j]);
	}
	dp[0]=1;
	for(int i=1;i<=n;++i)dp=(dp<<foo[i])|(dp<<bar[i]);
	scanf("%d",&q);
	for(int i=1,k;i<=q;++i){
		scanf("%d",&k);
		puts(dp[k]?"Orz":"QAQ");
	}
	return 0;
}

上一题