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

    这题有多种做法,一种是倍增预处理出每个点往上走2^i步最少需要的初始战斗力,一种是裸的启发式合并带标记splay。

    每个点合并能攻占其儿子的所有骑士,删去所有无法攻占这个城市的骑士并记录答案。

    注意到splay每次实际上只需要取出最小的元素判断是否牺牲,这显然可以用堆维护。

    关于可并堆打标记:和线段树打标记一样,维护乘法标记a和加法标记b,所有元素表示为ax+b,用同样的方法下传。

    注意merge前要先push。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=300010;
     9 int n,m,cnt,a[N],fa[N],rt[N],bg[N],ed[N],ls[N],rs[N],dis[N],dep[N],dead[N],to[N],nxt[N],h[N];
    10 ll mul[N],plu[N],v[N],p[N],d[N];
    11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    12 
    13 void put(int x,ll a,ll b){
    14     if (!x) return;
    15     v[x]=v[x]*a+b; mul[x]*=a; plu[x]=plu[x]*a+b;
    16 }
    17 
    18 void push(int x){
    19     put(ls[x],mul[x],plu[x]); put(rs[x],mul[x],plu[x]);
    20     mul[x]=1; plu[x]=0;
    21 }
    22 
    23 int merge(int x,int y){
    24     if (!x || !y) return x+y;
    25     push(x); push(y);
    26     if (v[x]>v[y]) swap(x,y);
    27     rs[x]=merge(rs[x],y);
    28     if (dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
    29     dis[x]=dis[rs[x]]+1; return x;
    30 }
    31 
    32 int pop(int x){ push(x); return merge(ls[x],rs[x]); }
    33 
    34 void dfs(int x,int fa){
    35     dep[x]=dep[fa]+1;
    36     For(i,x) dfs(k=to[i],x),rt[x]=merge(rt[x],rt[k]);
    37     while (rt[x] && v[rt[x]]<d[x])
    38         dead[x]++,ed[rt[x]]=x,rt[x]=pop(rt[x]);
    39     if (!a[x]) put(rt[x],1,p[x]); else put(rt[x],p[x],0);
    40 }
    41 
    42 int main(){
    43     freopen("bzoj4003.in","r",stdin);
    44     freopen("bzoj4003.out","w",stdout);
    45     scanf("%d%d",&n,&m);
    46     rep(i,1,n) scanf("%lld",&d[i]);
    47     rep(i,2,n) scanf("%d%d%lld",&fa[i],&a[i],&p[i]),add(fa[i],i);
    48     rep(i,1,m) mul[i]=1,scanf("%lld%d",&v[i],&bg[i]),rt[bg[i]]=merge(rt[bg[i]],i);
    49     dfs(1,0);
    50     rep(i,1,n) printf("%d
    ",dead[i]);
    51     rep(i,1,m) printf("%d
    ",dep[bg[i]]-dep[ed[i]]);
    52     return 0;
    53 }
  • 相关阅读:
    linux下开启防火墙,允许通过的端口
    linux下限定连接ip和端口
    centos7关闭防火墙
    linux下清空文件内容的3个命令
    yum安装软件包提示Error Downloading Packages解决方法
    Zabbix 监控服务介绍
    Redis 应用
    分布式中间件MyCat 使用
    DevOps Gitlab环境部署
    MySQL Atlas 读写分离软件介绍
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9878908.html
Copyright © 2011-2022 走看看