zoukankan      html  css  js  c++  java
  • [洛谷P3261] [JLOI2015]城池攻占(左偏树)

    不得不说,这道题目是真的难,真不愧它的“省选/NOI-”的紫色大火题!!!

    花了我晚自习前半节课看题解,写代码,又花了我半节晚自习调代码,真的心态爆炸。基本上改得和题解完全一样了我才过了这道题!真的烦。没事,那接下来我来完全把这道题搞透。

    左偏树总结

    Part 1 理解题目

    至少我一开始不知道为什么要用左偏树,甚至我看题解一开始也都没弄懂,所以先把题目弄清楚。
    首先我们由题可以知道,这要求我们从建好的树的叶子节点开始往上推,有些骑士到特定的点才会出现,check一下骑士能否攻占城池,再记录进答案,更新战斗力,这就很容易想到左偏树可并堆了。

    Part 2 解题思想

    既然每到一个点会出现一堆的新骑士,所以我们可以在那些点连一些“隐藏边”,到这个点时用链式前向星扫一遍加到一个小根堆中,然后把这个点以下的所有剩下的骑士合并到这个堆中(板子),然后在check时挨个弹出堆顶,如果不能占领就记入答案,能占领我们就要考虑更新骑士,我们不可能直接更新整个堆中的骑士,这样会被硬生生卡成O(n)的修改,所以我们考虑放一个lazy标记在堆顶,每一次合并和删除的时候再下放就可以了。

    part 3 code

        #include<iostream>  
        #include<cstdlib>  
        #include<cstdio>  
        #include<cmath>  
        #include<cstring>  
        #include<iomanip>  
        #include<algorithm>  
        #include<ctime>  
        #include<queue>  
        #include<stack>  
        #define lst long long  
        #define rg register  
        #define N 300050  
        using namespace std;  
          
        int n,m,cnt;  
        bool type[N];  
        int fir[N],deep[N],up[N],dead[N];  
        lst key[N],def[N],v[N],mul[N],plu[N];  
        struct edge{  
            int to,nxt;  
        }a[N],b[N];  
        int head[N],ft[N],ls[N],rs[N],dis[N];  
          
        inline lst read()  
        {  
            rg lst s=0,m=1;rg char ch=getchar();  
            while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();  
            if(ch=='-')m=-1,ch=getchar();  
            while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();  
            return m*s;  
        }  
          
        void cover(rg int A,rg lst c,rg lst j)  
        {  
            if(!A)return;  
            key[A]*=c,key[A]+=j;  
            mul[A]*=c,plu[A]*=c,plu[A]+=j;  
        }  
          
        void pushdown(rg int A)  
        {  
            cover(ls[A],mul[A],plu[A]);  
            cover(rs[A],mul[A],plu[A]);  
            mul[A]=1,plu[A]=0;  
        }  
          
        int Merge(rg int A,rg int B)  
        {  
            if(!A||!B)return A+B;  
            if(key[A]>key[B])swap(A,B);  
            pushdown(A),pushdown(B);  
            rs[A]=Merge(rs[A],B);  
            if(dis[ls[A]]<dis[rs[A]])swap(ls[A],rs[A]);  
            dis[A]=dis[rs[A]]+1;  
            return A;  
        }  
          
        int Delete(rg int A)  
        {  
            pushdown(A);  
            return Merge(ls[A],rs[A]);  
        }  
          
        int dfs(rg int now,rg int fm)  
        {  
            rg int A=0,B;  
            deep[now]=deep[fm]+1;  
            for(rg int i=ft[now];i;i=b[i].nxt)A=Merge(A,b[i].to);  
            for(rg int i=head[now];i;i=a[i].nxt)  
            {  
                B=dfs(a[i].to,now);  
                A=Merge(A,B);  
            }  
            while(key[A]<def[now]&&A)  
            {  
                dead[now]++;up[A]=deep[now];  
                A=Delete(A);  
            }  
            if(type[now])cover(A,v[now],0);  
            else cover(A,1,v[now]);  
            return A;  
        }  
          
        int main()  
        {  
            n=read(),m=read();  
            for(rg int i=1;i<=n;++i)def[i]=read();  
            for(rg int i=2;i<=n;++i)  
            {  
                rg int go=read();  
                a[++cnt]=(edge){i,head[go]};head[go]=cnt;  
                type[i]=read(),v[i]=read();  
            }cnt=0;  
            for(rg int i=1;i<=m;++i)  
            {  
                key[i]=read(),fir[i]=read();  
                b[++cnt]=(edge){i,ft[fir[i]]};ft[fir[i]]=cnt;  
            }  
            dfs(1,0);  
            for(rg int i=1;i<=n;++i)printf("%d
    ",dead[i]);  
            for(rg int i=1;i<=m;++i)printf("%d
    ",deep[fir[i]]-up[i]);  
            return 0;  
        }  

    到此为止,顺便膜拜一下大佬zsy,这是他的城池攻占:666





    哪怕人间是炼狱,梦想永远是天堂
    继续走下去吧,理想永远都年轻,花儿一定会再次盛开
  • 相关阅读:
    函数式编程
    scala 有 + 运算符吗?
    使用 Idea 打 scala程序的 jar 包
    相见恨晚的 scala
    半夜思考,为什么 String 具有不变性
    我的常用
    DataTable学习笔记
    Js 操作cookie
    嵌套的 ajax 请求
    Jquery插件收集【m了慢慢学】
  • 原文地址:https://www.cnblogs.com/cjoierljl/p/8641030.html
Copyright © 2011-2022 走看看