JLOI2015城池攻占 左偏树

分析

什么是左偏树
先来考虑暴力做法,对于每个骑士都做一遍DFS,时间复杂度\(O(NM)\),显然会T。
接着考虑一下优化,因为只有这么一棵树,并且,每个骑士不会相互影响,既然这样,那么就只跑一遍DFS,然后一起处理所有的骑士,是不是就可以了呢?但如果我们再遍历一下这个节点的骑士,好像还是没有优化,接着我们想,如果这堆骑士中攻击力最小的那个都能攻下这个节点,那么显然所有的城市都能攻下这个节点,而题目又没有问有多少骑士能过去,问的是多少死在这里了,所以就从攻击力小的开始遍历一下就行。
每一次都sort显然不是我们想要的,动态维护最小值用小根堆,但是这题又涉及到了合并,于是不难想到用左偏树-可并堆。
这里还有一个问题,就是骑士的攻击力还有变化,那怎么办?参照线段树的写法写一个区间修改就行。
对于加法,直接加,对于乘法,把加法标记和值都乘一下。

#include
#include
#include
#define ll long long
using namespace std;
const int N=3e5+10;
struct ltt{
	ll val,dis,laz1,laz2,s,c;
	int ls,rs,fa;
}T[N];
struct Node{
	ll f,a,v,h;
}p[N];
struct Edge{
	int to,nxt;
}e[N];
int h[N],idx;
void Ins(int a,int b){
	e[++idx].to=b;e[idx].nxt=h[a];h[a]=idx;
}
#define ls(x) T[x].ls
#define rs(x) T[x].rs
int rt[N],dep[N];
ll ans1[N],ans2[N];
inline void pushdown(int x){
	if(ls(x)){
		T[ls(x)].s=T[ls(x)].s*T[x].laz1+T[x].laz2;
		T[ls(x)].laz1*=T[x].laz1;
		T[ls(x)].laz2=T[ls(x)].laz2*T[x].laz1+T[x].laz2;
	}
	if(rs(x)){
		T[rs(x)].s=T[rs(x)].s*T[x].laz1+T[x].laz2;
		T[rs(x)].laz1*=T[x].laz1;
		T[rs(x)].laz2=T[rs(x)].laz2*T[x].laz1+T[x].laz2;
	}
	T[x].laz1=1;T[x].laz2=0;
}
int merge(int x,int y){
	if(!x||!y)return x+y;
	if(T[x].s>T[y].s)swap(x,y);
	pushdown(x),pushdown(y);
	rs(x)=merge(rs(x),y);
	if(T[ls(x)].dis

你可能感兴趣的:(JLOI2015城池攻占 左偏树)