zoukankan      html  css  js  c++  java
  • @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 年前的题就让我自闭了,深深感到自己的弱。

  • 相关阅读:
    如何将网格式报表打印成其它样式
    拥有与实力不相称的脾气是种灾难——北漂18年(23)
    8.8.1 Optimizing Queries with EXPLAIN
    mysql 没有rowid 怎么实现根据rowid回表呢?
    secondary index
    8.5.5 Bulk Data Loading for InnoDB Tables 批量数据加载
    mysql 中key 指的是索引
    8.5.4 Optimizing InnoDB Redo Logging 优化InnoDB Redo 日志
    8.5.3 Optimizing InnoDB Read-Only Transactions 优化InnoDB 只读事务
    8.5.1 Optimizing Storage Layout for InnoDB Tables InnoDB表的存储布局优化
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12420629.html
Copyright © 2011-2022 走看看