题解 - 【BZOJ 2827】千山鸟飞绝

题面简述:

话说有一天 doyouloveme 和 vfleaking 到山里玩。谁知 doyouloveme 刚刚进山,所有的鸟儿竟被他的神犇气场给惊得全部飞走了。vfleaking 顿时膜拜不已。

这时鸟王用鸟语说道:“!@#¥%……?”安抚了一下众鸟的情绪。鸟王生性好斗,作出了一个决定——要排鸟布阵把刚才吓到它们的人类赶出山去。

每只鸟都有一个编号,都有一个威武值。每秒钟鸟王都会发一个命令,编号为 \(v\) 的鸟飞到 \((x,y)\) 去(坐标系原点是山顶,坐标单位为鸟爪)。

鸟飞得很快,一秒之内就飞到了,可以看作是瞬间移动。如果编号为 \(v\) 的鸟和编号为 \(u\) 的鸟某一时刻处在同一位置,它们就会互相鼓励,增加各自的士气值和团结值。

一只鸟的士气值等于此刻与它处在同一位置的鸟中的威武值的最大值,团结值等于此刻与它处在同一位置的鸟的只数。如果每一时刻都没有鸟与它处在同一位置,则士气值和团结值都为 \(0\) 。要注意自己不能鼓励自己,计算士气值和团结值时不能算上自己。

t 秒钟后,doyouloveme 目测出了现在每只鸟的战斗力,于是感叹了一句:“不妙,我们得走了。”

正所谓团结的鸟儿一个顶俩,所以 doyouloveme 这样描述战斗力:一只鸟战斗力值等于它在 \(0\)\(t\) 秒中士气值的最大值与团结值的最大值的乘积。注意不是乘积的最大值,而是最大值的乘积。

vfleaking 很想知道现在每只鸟的战斗力,但是他当然不会啦,于是他把这个任务交给了你来完成。

思路

对坐标进行离散化,对每一个位置建立Splay, 之后只要维护最大值,次大值,和鸟的个数即可。

实现

这个东西的话由于使用 map 的话一次存储 \(2\) 个点会超时,所以考虑两个点压成一个点存储,也即弄成: \((x,y) = x \times p + y\) (其中, \(p\) 是一个很大的数)

剩下直接用模板即可。

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define maxn 1000001
#define p 1e9
using namespace std;

int n, m, cnt, W[maxn], ans[maxn], ans2[maxn], ss[maxn];

inline int read() {
    int x = 0;
    bool f = 0; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = 1; c = getchar();}
    while ('0' <= c && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}
    if (f) {
        x = -x;
    }
    return x;
}


template<typename T>
inline T m_max(T x,T y){return x>y?x:y;}
struct dian {
    int x, y;
};
bool operator < (dian a, dian b) {
    if (a.x != b.x) {
        return a.x < b.x;
    }
    return a.y < b.y;
}
unordered_map <long long, int > mp;
struct Treap {
	Treap *ch[2];
	int v,s,r,ma,ms;
	Treap(int x=0):v(x),s(1),ma(0),ms(0),r(rand()) {
		ch[0]=ch[1]=NULL;
	}
	inline int sz() {
		return this?this->s:0;
	}
	inline void reval(int x,int y) {
		if(!this) return;
		this->ma=m_max(this->ma,x);
		this->ms=m_max(this->ms,y);
		ans[this->v]=m_max(ans[this->v],x);
		ans2[this->v]=m_max(ans2[this->v],y);
	}
	inline void mt() {
		if(!this) return;
		this->s=this->ch[0]->sz()+this->ch[1]->sz()+1;
	}
	inline void dn() {
		if(!this) return;
		if(!this->ma&&!this->ms) return;
		this->ch[0]->reval(this->ma,this->ms);
		this->ch[1]->reval(this->ma,this->ms);
		this->ma=this->ms=0;
	}
	inline void rotate(Treap*& now,int d) {
		Treap* k=now->ch[d^1];
		now->dn();
		k->dn();
		now->ch[d^1]=k->ch[d];
		k->ch[d]=now;
		now->mt();
		k->mt();
		now=k;
	}
	inline void insert(Treap*& now,int x) {
		if(!now) {
			now=new Treap(x);
			return;
		}
		now->dn();
		int d;
		if(W[x]<W[now->v]||(W[x]==W[now->v]&&x<now->v)) d=0; else d=1;
		insert(now->ch[d],x);
		if(now->ch[d]->r < now->r) rotate(now,d^1);
		now->mt();
	}
	inline void del(Treap*& now,int x) {
		now->dn();
		if(W[now->v]==W[x]&&now->v==x) {
			if(now->ch[0]&&now->ch[1]) {
				int d=now->ch[0]->r < now->ch[1]->r;
				rotate(now,d);
				del(now->ch[d],x);
			} else {
				Treap* tmp=now;
				now=now->ch[0]?now->ch[0]:now->ch[1];
				delete tmp;
			}
		} else {
			if(W[now->v]>W[x]||(W[now->v]==W[x]&&now->v>x)) del(now->ch[0],x); else del(now->ch[1],x);
		}
		if(now) now->mt();
	}
	inline int gmax(Treap* now) {
		if(!now->ch[1]) return W[now->v];
		return gmax(now->ch[1]);
	}
} *root[maxn];

int main() {
    freopen("bird.in", "r", stdin);
    freopen("bird.out", "w", stdout);
    
    n = read();
    for (int i = 1; i <= n; ++i) {
        dian d;
        W[i] = read();
        d.x = read();
        d.y = read();
        
        long long x = d.x * p + d.y;
        if (!mp.count(x)) {
            mp[x] = ++cnt;
        }
        int now = mp[x];
        ss[i] = now;
        if (root[now]) {
            ans[i] = m_max(ans[i], root[now] -> gmax(root[now])), root[now] -> reval(W[i], 0);
        }
        root[now] -> insert(root[now], i);
        root[now] -> reval(0, root[now] -> sz() - 1);
    }
    scanf("%d", &m);
    
    for (int i = 1; i <= m; ++i) {
        dian s;
        int d;
        d = read();
        s.x = read();
        s.y = read();
        
        long long x = s.x * p + s.y;
        if (!mp.count(x)) {
            mp[x] = ++cnt;
        }
        int now = mp[x];
        root[ss[d]] -> del(root[ss[d]], d);
        ss[d] = now;
        if (root[now]) {
            ans[d] = m_max(ans[d], root[now] -> gmax(root[now])), root[now] -> reval(W[d], 0);
        }
        root[now] -> insert(root[now], d);
        root[now] -> reval(0, root[now] -> sz() - 1);
    }
    for (int i = 1; i <= n; ++i) {
        root[ss[i]] -> del(root[ss[i]], i);
    }
    for (int i = 1; i <= n; ++i) {
        printf("%lld\n", 1ll * ans[i] * ans2[i]);
    }
}

猜你喜欢

转载自www.cnblogs.com/littlefrog/p/13189288.html
今日推荐