zoukankan      html  css  js  c++  java
  • @codeforces


    @description@

    有 n 件 T-shirt,第 i 件 T-shirt 有一个 ci 和 qi,分别表示费用与质量。
    同时有 k 个顾客,第 j 个顾客准备了 bj 的金钱去购买 T-shirt。

    每个顾客的购买策略是相同的:
    他会买他的资金范围内 q 值最大的一件,如果有多个选 c 最小的一件,每种 T-shirt 只买1 次。
    重复购买,直到所有的 T-shirt 他都买不起或者他都买过了。

    求每位顾客最终可以购买的 T-shirt 数量。

    Input
    第一行一个整数 n (1 ≤ n ≤ 2·10^5),表示 T-shirt 的种类数。
    接下来 n 行,每行两个整数 ci 与 qi (1 ≤ ci, qi ≤ 10^9),含义如上。
    接下来一行一个正整数 k (1 ≤ k ≤ 2·10^5) ,表示顾客数。
    接下来 k 个正整数 b1, b2, ..., bk (1 ≤ bj ≤ 10^9)。

    Output
    输出一行 k 个整数,表示第 i 个人买的 T-shirt。

    Examples
    Input
    3
    7 5
    3 5
    4 3
    2
    13 14
    Output
    2 3

    Input
    2
    100 500
    50 499
    4
    50 200 150 100
    Output
    1 2 2 1

    @solution@

    假如我们把人当作询问,T-shirt 当作元素,则至少我是想不出什么办法快速维护求出询问的。

    但是反过来——我们按照 T-shirt 的优先级从大到小排序,把每个 T-shirt 当作一次修改,然后对人进行统一地修改,就很有戏了。
    假如一个 T-shirt 的价格是 c,则我们的修改步骤就是先找出 >= c 的人,将这些人所拥有的钱减去 c,将这些人所拥有的 T-shirt 数量加上 1。

    貌似可以用平衡树来 merge 和 split。但是注意,我们只能 merge 两个值域没有交集的平衡树,而减去 c 过后可能就产生了交集。
    我们将 >= c 的人分为两类。第一类是 >= 2*c 的,这一部分减去 c 依然可以直接 merge;第二类是 < 2*c 的,这一类减去 c 过后只能一个个暴力插入。

    因为第二类的人一定满足 c <= x < 2*c,每一次 x 至少折半,这样每个人只会被暴力插入 O(log)
    于是就 O(nlog^2n) 的总复杂度。因为是 codeforces 所以能过。

    @accepted code@

    #include<cstdlib>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int MAXN = 200000;
    struct treap{
    	struct node{
    		node *ch[2];
    		int key, tg1;
    		int sum, tg2;
    		unsigned int pri;
    	}pl[MAXN + 5], *ncnt, *NIL;
    	#define mp make_pair
    	#define fi first
    	#define se second
    	typedef pair<node*, node*> Droot;
    	unsigned int get_rand() {return (rand() << 16) | rand();}
    	treap() {
    		NIL = ncnt = &pl[0];
    		NIL->ch[0] = NIL->ch[1] = NIL;
    		NIL->key = NIL->tg1 = NIL->sum = NIL->tg2 = 0;
    		NIL->pri = -1;
    	}
    	node *newnode(int k) {
    		node *p = (++ncnt);
    		p->ch[0] = p->ch[1] = NIL;
    		p->key = k, p->tg1 = p->sum = p->tg2 = 0;
    		p->pri = get_rand();
    		return p;
    	}
    	void maintain1(node *x, int k) {if( x != NIL ) x->key += k, x->tg1 += k;}
    	void maintain2(node *x, int k) {if( x != NIL ) x->sum += k, x->tg2 += k;}
    	void pushdown(node *rt) {
    		if( rt->tg1 ) {
    			maintain1(rt->ch[0], rt->tg1), maintain1(rt->ch[1], rt->tg1);
    			rt->tg1 = 0;
    		}
    		if( rt->tg2 ) {
    			maintain2(rt->ch[0], rt->tg2), maintain2(rt->ch[1], rt->tg2);
    			rt->tg2 = 0;
    		}
    	}
    	node *merge(node *x, node *y) {
    		if( x == NIL ) return y;
    		if( y == NIL ) return x;
    		pushdown(x), pushdown(y);
    		if( x->pri < y->pri ) {
    			x->ch[1] = merge(x->ch[1], y);
    			return x;
    		}
    		else {
    			y->ch[0] = merge(x, y->ch[0]);
    			return y;
    		}
    	}
    	Droot split(node *rt, int k) {
    		if( rt == NIL ) return mp(NIL, NIL);
    		pushdown(rt);
    		if( rt->key < k ) {
    			Droot p = split(rt->ch[1], k);
    			rt->ch[1] = p.fi; return mp(rt, p.se);
    		}
    		else {
    			Droot p = split(rt->ch[0], k);
    			rt->ch[0] = p.se; return mp(p.fi, rt);
    		}
    	}// < k, >= k
    	node *insert(node *rt, node *x) {
    		Droot p = split(rt, x->key);
    		return merge(p.fi, merge(x, p.se));
    	}
    	void push(node *&rt, node *x) {
    		if( x == NIL ) return ;
    		pushdown(x);
    		push(rt, x->ch[0]), push(rt, x->ch[1]);
    		x->ch[0] = x->ch[1] = NIL;
    		rt = insert(rt, x);
    	}
    	node *update(node *rt, int k) {
    		Droot p = split(rt, k);
    		if( p.se == NIL ) return merge(p.fi, p.se);
    		p.se->key -= k, p.se->tg1 -= k;
    		p.se->sum += 1, p.se->tg2 += 1;
    		Droot q = split(p.se, k);
    		if( q.fi != NIL ) push(p.fi, q.fi);
    		return merge(p.fi, q.se);
    	}
    	void dfs(node *x) {
    		if( x == NIL ) return ;
    		pushdown(x);
    		dfs(x->ch[0]), dfs(x->ch[1]);
    	}
    }T;
    treap::node *nd[MAXN + 5], *rt;
    struct Tshirt{
    	int c, q;
    	Tshirt(int _c=0, int _q=0):c(_c), q(_q) {}
    	friend bool operator < (Tshirt a, Tshirt b) {
    		return (a.q == b.q) ? a.c < b.c : a.q > b.q;
    	}
    }t[MAXN + 5];
    int ans[MAXN + 5];
    int read() {
    	int x = 0; char ch = getchar();
    	while( ch > '9' || ch < '0' ) ch = getchar();
    	while( '0' <= ch && ch <= '9' ) x = 10*x + ch - '0', ch = getchar();
    	return x;
    }
    int main() {
    	int n = read(), k;
    	srand(n ^ 0307);
    	for(int i=1;i<=n;i++)
    		t[i].c = read(), t[i].q = read();
    	sort(t + 1, t + n + 1);
    	k = read(), rt = T.NIL;
    	for(int i=1;i<=k;i++)
    		rt = T.insert(rt, nd[i] = T.newnode(read()));
    	for(int i=1;i<=n;i++)
    		rt = T.update(rt, t[i].c);
    	T.dfs(rt);
    	for(int i=1;i<=k;i++)
    		printf("%d ", nd[i]->sum);
    }
    

    @details@

    思路本身还是很巧妙的。
    而且也印证了非旋 treap 是一种非常优美的数据结构,因为基本上没有什么实现难度。

  • 相关阅读:
    预编译
    AndroidRuntime: android.app.RemoteServiceException: Bad notification posted from package
    RadioButton和RadioGroup一点使用心得
    POJ 2774 Long Long Message 后缀数组
    POJ 2406 Power String 后缀数组
    URAL 1297 Palindrome 后缀数组+RMQ
    SPOJ 694 705 后缀数组
    POJ 3261 Milk Patterns 后缀数组
    POJ 1743 Musical Theme 后缀数组
    HDU 5040 Instrusive BFS
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11693185.html
Copyright © 2011-2022 走看看