zoukankan      html  css  js  c++  java
  • JLOI2015城池攻占 左偏树

    分析

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

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #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<T[rs(x)].dis)
    		swap(ls(x),rs(x));
    	T[x].dis=T[rs(x)].dis+1;
    	return x;
    }
    void dfs(int u,int fa){
    	dep[u]=dep[fa]+1;
    	for(int i=h[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		dfs(v,u);
    		rt[u]=merge(rt[u],rt[v]);
    	}
    	while(rt[u]&&T[rt[u]].s<p[u].h){
    		pushdown(rt[u]);
    		ans1[u]++;
    		ans2[rt[u]]=dep[T[rt[u]].c]-dep[u];
    		rt[u]=merge(ls(rt[u]),rs(rt[u]));
    	}
    	if(p[u].a==1){
    		T[rt[u]].s*=p[u].v;
    		T[rt[u]].laz1*=p[u].v;
    		T[rt[u]].laz2*=p[u].v;
    	}
    	if(p[u].a==0){
    		T[rt[u]].s+=p[u].v;
    		T[rt[u]].laz2+=p[u].v;
    	}
    }
    int main(){
    	ll n,m;
    	scanf("%lld%lld",&n,&m);
    	for(register int i=1;i<=n;i++)
    		scanf("%lld",&p[i].h);
    	for(register int i=2;i<=n;i++)
    		scanf("%lld%lld%lld",&p[i].f,&p[i].a,&p[i].v),Ins(p[i].f,i);
    	for(register int i=1;i<=m;i++){
    		scanf("%lld%lld",&T[i].s,&T[i].c);
    		T[i].laz1=1;
    		rt[T[i].c]=merge(rt[T[i].c],i);
    	}
    	dfs(1,0);
    	while(rt[1]){
    		pushdown(rt[1]);
    		ans2[rt[1]]=dep[T[rt[1]].c];
    		rt[1]=merge(ls(rt[1]),rs(rt[1]));
    	}
    	for(int i=1;i<=n;i++)
    		printf("%lld
    ",ans1[i]);
    	for(int i=1;i<=m;i++)
    		printf("%lld
    ",ans2[i]);
    }
    
  • 相关阅读:
    思维探索者:理解了才是真正的学习 理解会带来巨大的好处
    思维探索者:让记忆与学习更有效率 别在别人的思考中得意着
    思维探索者:从问题到答案的思维过程 像侦探一样思考
    android-HttpClient上传信息(包括图片)到服务端
    java web每天定时执行任务
    基础总结篇之一:Activity生命周期
    Spring面试题一
    J2EE用监听器实现同一用户只能有一个在线
    notepad++快捷键大全
    python for循环巧妙运用(迭代、列表生成式)
  • 原文地址:https://www.cnblogs.com/anyixing-fly/p/12928200.html
Copyright © 2011-2022 走看看