• @bzoj



    @description@

    终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的关键人物——小蓝的好友。

    在帮小蓝确定了旅游路线后,小蓝的好友也不会浪费这个难得的暑假。与小蓝不同,小蓝的好友并不想将时间花在旅游上,而是盯上了最近发行的即时战略游戏——SangoCraft。但在前往通关之路的道路上,一个小游戏挡住了小蓝的好友的步伐。

    “国家的战争其本质是抢夺资源的战争”是整款游戏的核心理念,这个小游戏也不例外。简单来说,用户需要在给定的长方形土地上选出一块子矩形,而系统随机生成了N个资源点,位于用户所选的长方形土地上的资源点越多,给予用户的奖励也越多。悲剧的是,小蓝的好友虽然拥有着极其优秀的能力,但同时也有着极差的RP,小蓝的好友所选的区域总是没有一个资源点。

    终于有一天,小蓝的好友决定投诉这款游戏的制造厂商,为了搜集证据,小蓝的好友想算出至少包含一个资源点的区域的数量。作为小蓝的好友,这自然是你分内之事。

    原题传送门。

    @solution@

    简单容斥转成求不包含任何资源点的区域数量。

    这个经典问题做法很多,但必须要利用题设(随机,资源点个数少)才能得到合理的时间复杂度。

    考虑一种基于笛卡尔树的做法:枚举最下面的一行,计算每一列往上最长延伸的长度 len,以长度为关键字从小到大建立笛卡尔树。
    这样一来笛卡尔树中每个点的贡献为 (len[x] - len[fa]) * (siz[x] * (siz[x] + 1) / 2),答案为贡献之和。

    因为笛卡尔树本质就是 treap,所以可以从上往下扫描的同时用 treap 维护出笛卡尔树及其对应的信息即可。
    因为点随机,所以笛卡尔树(treap)的期望高度为 O(log),因此就可以 O(nlog n) 通过该题。

    @accepted code@

    #include <cstdio>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    typedef long long ll;
    #define mp make_pair
    #define fi first
    #define se second
    
    const int MAXN = 40000;
    
    struct treap{
    	struct node{
    		ll sum, val;
    		int pri, key, tag, siz;
    		node *ch[2], *fa;
    	}pl[MAXN + 5], *NIL, *ncnt;
    	typedef pair<node*, node*> Droot;
    	treap() {
    		NIL = ncnt = pl;
    		NIL->ch[0] = NIL->ch[1] = NIL->fa = NIL;
    		NIL->key = NIL->pri = NIL->tag = NIL->siz = 0, NIL->sum = NIL->val = 0;
    	}
    	node *newnode(int k) {
    		node *p = (++ncnt);
    		p->ch[0] = p->ch[1] = p->fa = NIL;
    		p->key = k, p->siz = 1, p->tag = p->pri = 0, p->sum = p->val = 0;
    		return p;
    	}
    	void pushup(node *x) {
    		x->siz = x->ch[0]->siz + x->ch[1]->siz + 1;
    		x->val = 1LL * x->siz * (x->siz + 1) * (x->pri - x->fa->pri) / 2;
    		x->sum = x->ch[0]->sum + x->ch[1]->sum + x->val;
    	}
    	void maintain(node *x, int k) {
    		if( x != NIL ) x->tag += k, x->pri += k, pushup(x);
    	}
    	void pushdown(node *x) {
    		if( x->tag ) {
    			maintain(x->ch[0], x->tag);
    			maintain(x->ch[1], x->tag);
    			x->tag = 0;
    		}
    	}
    	void set_child(node *x, node *y, int d) {
    		if( y != NIL ) y->fa = x, pushup(y);
    		if( x != NIL ) x->ch[d] = y, pushup(x);
    	}
    	node *merge(node *x, node *y) {
    		if( x == NIL ) return y;
    		if( y == NIL ) return x;
    		if( x->pri < y->pri ) {
    			pushdown(x), x->ch[1]->fa = NIL;
    			set_child(x, merge(x->ch[1], y), 1);
    			return x;
    		}
    		else {
    			pushdown(y), y->ch[0]->fa = NIL;
    			set_child(y, merge(x, y->ch[0]), 0);
    			return y;
    		}
    	}
    	Droot split(node *x, int k) {
    		if( x == NIL ) return mp(NIL, NIL);
    		pushdown(x);
    		if( x->key <= k ) {
    			x->ch[1]->fa = NIL; Droot p = split(x->ch[1], k);
    			set_child(x, p.fi, 1); return mp(x, p.se);
    		}
    		else {
    			x->ch[0]->fa = NIL; Droot p = split(x->ch[0], k);
    			set_child(x, p.se, 0); return mp(p.fi, x);
    		}
    	}// key <= k ; key > k
    	node *modify(node *rt, int k) {
    		Droot p = split(rt, k), q = split(p.fi, k - 1);
    		q.se->pri = 0, pushup(q.se);
    		return merge(merge(q.fi, q.se), p.se);
    	}
    }T;
    typedef pair<treap::node*, treap::node*> Droot;
    /*
    (pri[x] - pri[fa[x]]) * (siz[x]*siz[x] + siz[x]) / 2
    */
    
    vector<int>v[MAXN + 5];
    treap::node *nd[MAXN + 5], *rt;
    
    treap::node *build(int l, int r) {
    	if( l > r ) return T.NIL;
    	int m = (l + r) >> 1; nd[m] = T.newnode(m);
    	T.set_child(nd[m], build(l, m - 1), 0);
    	T.set_child(nd[m], build(m + 1, r), 1);
    	return nd[m];
    }
    
    int main() {
    	int R, C, N; scanf("%d%d%d", &R, &C, &N), rt = build(1, C);
    	for(int i=1;i<=N;i++) {
    		int x, y; scanf("%d%d", &x, &y);
    		v[x].push_back(y);
    	}
    	ll ans = 1LL*R*(R + 1)/2*C*(C + 1)/2;
    	for(int i=1;i<=R;i++) {
    		T.maintain(rt, 1);
    		for(int j=0;j<v[i].size();j++)
    			rt = T.modify(rt, v[i][j]);
    		ans -= rt->sum;
    	}
    	printf("%lld
    ", ans);
    }
    

    @details@

    记得开 long long。

    一看才发现是 ZJOI2012 的题,发现一道 8 年前的题就让我自闭了,深深感到自己的弱。

  • 相关阅读:
    An easy problem
    Big Event in HDU
    第二个div+css前端项目
    第一个网站前端
    通过jquery.transit.min.js插件,实现图片的移动
    anchor_target_layer中的bounding regression
    faster rcnn结构
    论文灵感
    anchor_target_layer层其他部分解读
    numpy add
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12420629.html
Copyright © 2020-2023  润新知