CF(173E) Camping Groups

题目链接

题意:一个俱乐部有 n名成员,每名成员有两个属性:声望r和年纪a(均为109)。若干个个可以组成一个小组,每个小组中有一名组长,要求这名组长的声望高于其他成员且这名组长与组内任意成员的年龄差小于k,先给出10000条查询,问如果a、b两人在一个小组中,那么这个小组最多可以有多少人。

解法:1.由于n和a相差很大,因此首先要对声望和年纪进行离散化

          2.每个小组的最大成员数量由队长决定,因此问题变为选一个在与ab年纪差均小于k的人中选一个其作为组长人数最多的一个,因此需要离线处理出每个人作为组长小组内的人数,由于每个人只能作为声望小于等于自己的人的组长,因此先按声望由小到大排序然后依次处理,用树状数组统计出当前年纪在a-k和a+k范围内有多少人(由于是对离散化后的数据进行处理,因此要通过查询前驱和后继获取结果)

         3.按每条查询的声望值(两人声望中较大值)排序,并处理出每条查询两个人的组长的年龄范围:若a[i]<a[j],则可按a[j]-a[i]>k*2、k<a[j]-a[i]<=k*2、a[j]-a[i]<k三种情况讨论,然后对查询按由大到小处理,每次讲声望大于等于查询的队长的人数插入到线段树中,在查询年龄范围内的最大值(注意在去前去后继时判断无解的情况)

看别人的代码很简单,two pointers加点小数据结构就搞定了,这样做虽然很trivial但感觉比较直观。


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeMap;

public class CampingGroups173E {
	int maxn = 100010;
	class SegTree {
		class node {
			int left, right;
			int val;
			node(int l, int r) {
				left = l;
				right = r;
				val = -1;
			}
			int mid() {
				return (left + right) >> 1;
			}
		}
		node tree[] = new node[maxn * 3];
		void init(int idx, int l, int r) {
			tree[idx] = new node(l, r);
			if (l == r)
				return;
			int mid = tree[idx].mid();
			init(idx << 1, l, mid);
			init(idx << 1 | 1, mid + 1, r);
		}
		void update(int idx, int pos, int v) {
			if (pos == tree[idx].left & pos == tree[idx].right) {
				if (v > tree[idx].val)
					tree[idx].val = v;
				return;
			}
			int mid = tree[idx].mid();
			if (pos <= mid)
				update(idx << 1, pos, v);
			else
				update(idx << 1 | 1, pos, v);
			tree[idx].val = Math
					.max(tree[idx << 1].val, tree[idx << 1 | 1].val);
		}
		int query(int idx, int l, int r) {
			if (tree[idx].left == l && tree[idx].right == r)
				return tree[idx].val;
			int mid = tree[idx].mid();
			if (r <= mid)
				return query(idx << 1, l, r);
			if (l > mid)
				return query(idx << 1 | 1, l, r);
			return Math.max(query(idx << 1, l, mid),
					query(idx << 1 | 1, mid + 1, r));
		}
	}
	class Leader implements Comparable<Leader> {
		int age, cap, id;
		Leader(int i, int a, int c) {
			id = i;
			age = a;
			cap = c;
		}
		public int compareTo(Leader oth) {
			if (cap < oth.cap)
				return -1;
			return 1;
		}
	}
	class Query implements Comparable<Query> {
		int id;
		long left, right, cap, ans;
		Query(int i, int a, int b) {
			id = i;
			cap = Math.max(c[a], c[b]);
			if (age[a] > age[b]) {
				int temp = a;
				a = b;
				b = temp;
			}
			long temp = age[b] - age[a];
			if (temp > 2 * k) {
				ans = -1;
				return;
			}
			if (temp <= k) {
				left = age[a] - (k - temp);
				right = age[b] + (k - temp);
			} else if (temp <= 2 * k) {
				left = age[b] - k;
				right = age[a] + k;
			}
		}
		public int compareTo(Query oth) {
			if (cap > oth.cap)
				return -1;
			return 1;
		}
	}

	class IndexedTree {
		int n, ss[] = new int[maxn];
		int b[] = new int[maxn];
		IndexedTree() {
			for (int i = 1; i < maxn; i++)
				b[i] = i & (-i);
		}
		void init(int n) {
			this.n = n;
			Arrays.fill(ss, 0);
		}
		void inc(int i, int k) {
			while (i <= n) {
				ss[i] += k;
				i += b[i];
			}
		}
		int get(int i) {
			int res = 0;
			while (i > 0) {
				res += ss[i];
				i -= b[i];
			}
			return res;
		}
	}
	StreamTokenizer in = new StreamTokenizer(new BufferedReader(
			new InputStreamReader(System.in)));
	long next() throws IOException {
		in.nextToken();
		return (long) in.nval;
	}
	long age[] = new long[maxn], c[] = new long[maxn], k;
	SegTree st = new SegTree();
	IndexedTree it = new IndexedTree();
	Leader lead[] = new Leader[maxn];
	Query qq[] = new Query[maxn];
	TreeMap<Long, Integer> hashage = new TreeMap<Long, Integer>();
	TreeMap<Long, Integer> hashcap = new TreeMap<Long, Integer>();
	int n, m, cnt;
	void init() throws IOException {
		n = (int) next();
		k = next();
		for (int i = 1; i <= n; i++) {
			c[i] = next();
			hashcap.put(c[i], 0);
		}
		for (int i = 1; i <= n; i++) {
			age[i] = next();
			hashage.put(age[i], 0);
		}
		cnt = 0;
		Set<Long> set = hashcap.keySet();
		for (Long i : set)
			hashcap.put(i, ++cnt);
		cnt = 0;
		set = hashage.keySet();
		for (Long i : set)
			hashage.put(i, ++cnt);
		for (int i = 1; i <= n; i++)
			lead[i] = new Leader(i, hashage.get(age[i]), hashcap.get(c[i]));
		Arrays.sort(lead, 1, n + 1);
		m = (int) next();
		for (int i = 1; i <= m; i++)
			qq[i] = new Query(i, (int) next(), (int) next());
		Arrays.sort(qq, 1, m + 1);
	}
	int dp[] = new int[maxn];
	void work() {
		int i = 1;
		it.init(cnt);
		while (i <= n) {
			int j = i, temp = lead[j].cap;
			while (j <= n && lead[j].cap == temp)
				it.inc(lead[j++].age, 1);
			for (int p = i; p < j; p++) {
				int id = lead[p].id;
				int left = hashage.get(hashage.ceilingKey(age[id] - k));
				int right = hashage.get(hashage.floorKey(age[id] + k));
				dp[p] = it.get(right) - it.get(left - 1);
			}
			i = j;
		}
		st.init(1, 1, cnt);
		Arrays.fill(ans, -1);
	}
	int ans[] = new int[maxn];
	void query() {
		int ld = n;
		for (int i = 1; i <= m; i++) {
			int cap = hashcap.get(qq[i].cap);
			while (ld > 0 && lead[ld].cap >= cap)
				st.update(1, lead[ld].age, dp[ld--]);
			if (qq[i].ans != -1) {
				int left, right = 0;
				if (hashage.containsKey(qq[i].left))
					left = hashage.get(qq[i].left);
				else
					left = hashage.get(hashage.ceilingKey(qq[i].left));
				if (qq[i].right < hashage.firstKey())
					System.out.println(qq[i].id + " fuck");
				if (hashage.containsKey(qq[i].right))
					right = hashage.get(qq[i].right);
				else
					right = hashage.get(hashage.floorKey(qq[i].right));
				if (left <= right)
					ans[qq[i].id] = st.query(1, left, right);
			}
		}
	}

	void run() throws IOException {
		init();
		work();
		query();
		for (int i = 1; i <= m; i++)
			System.out.println(ans[i]);
	}
	public static void main(String[] args) throws IOException {
		new CampingGroups173E().run();
	}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值