zoukankan      html  css  js  c++  java
  • UOJ 284. 快乐游戏鸡

    倒着做。用lct维护

    我们把每个询问转化为总和减去大于等于最大权值的部分的后缀和。

    接着我们按w从大到小加入点,考虑维护每个点的子树中的最小深度

    这个怎么维护呢,考虑一个点肯定是更新它到根的路径,所以我们用类似LCT的access的方法更新,我们可以保证随时每个链的最小深度都相同,如果当前的链的最小深度小于用来更新的值就直接退出,否则的话我们就更新,最后再把这些更新了的链连起来。

    复杂度显然是 O((n+m)log⁡n)的,用类似证明LCT复杂度的方法证明即可。

    答案也很好算,记录一个后缀和即可,你会发现更新的时候也很好打标记,询问也很好处理。

    #include<bits/stdc++.h>
    #define Max(a,b) (a>b?a:b)
    #define nrt(x) (ch[fa[x]][0]==x||ch[fa[x]][1]==x)
    #define N 500007
    #define SI 23
    #define LL long long
    int Val[N],oo,val[N],fa[N],ch[N][2],dep[N],w[N],ma[N][SI],pos1[N],j;
    LL lazy[N],sum[N],ans[N];
    using namespace std;
    void write(LL x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
    inline void writeln(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('
    '); }
    inline void writel(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); }
    template <class T>
    inline void read(T& x){
        static char c; static int b;
        for (c=getchar(),b=1;!isdigit(c);c=getchar()) if (c=='-') b=-1;
        for (x=0;isdigit(c);c=getchar()) x=x*10+c-48;
        x*=b;
    }
    void rotate(int x) {
        int y=fa[x],z=fa[y],l,r;
        l=(ch[y][1]==x); r=l^1;
        if (nrt(y)) ch[z][ch[z][1]==y]=x;
        fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
        ch[y][l]=ch[x][r]; ch[x][r]=y;
    }
    void pushdown(int x){
        if (nrt(x)) pushdown(fa[x]);
        if (lazy[x]) {
            lazy[ch[x][0]]+=lazy[x]; lazy[ch[x][1]]+=lazy[x];
            sum[ch[x][0]]+=lazy[x]; sum[ch[x][1]]+=lazy[x];
            Val[ch[x][0]]=Val[x]; Val[ch[x][1]]=Val[x];
            lazy[x]=0;
        }
    }
    void splay(int x){
        pushdown(x);
        for (;nrt(x);) {
            int y=fa[x],z=fa[y];
            if (nrt(y)) 
             if (ch[y][1]==x^ch[z][1]==y) rotate(x); else rotate(y);
            rotate(x);
        }
    }
    //void access(int x){
    //    for (int t=0;x;t=x,x=fa[x]) splay(x),ch[x][1]=t;
    //}
    int t,p[N],need[N],n,q,qu,que,f[N][SI],pos2[N];
    void add(int y){
        if (!(f[y][0])) return; 
        for (int t=0,x=f[y][0];x;t=x,x=fa[x]) {
            splay(x);
            if (Val[x]<=dep[y]) break;
            lazy[x]+=(1ll*(dep[y]-(Val[x]==oo?0:Val[x]))*w[y]);
            sum[x]+=(1ll*(dep[y]-(Val[x]==oo?0:Val[x]))*w[y]);
            Val[x]=dep[y];
            ch[x][1]=0;
            if (lazy[x]) {
               lazy[ch[x][0]]+=lazy[x]; lazy[ch[x][1]]+=lazy[x];
               sum[ch[x][0]]+=lazy[x]; sum[ch[x][1]]+=lazy[x];
               Val[ch[x][0]]=Val[x]; Val[ch[x][1]]=Val[x];
               lazy[x]=0;
            }
            ch[x][1]=t; 
        }
        splay(f[y][0]);
    }
    inline LL query(int x,int y){
        splay(x);
        return sum[x]-(LL)(Val[x]==oo?0:Val[x])*y; 
    }
    signed main() {
        memset(Val,126,(sizeof Val)); oo=Val[0];
        read(n);
        for (int i=1;i<=n;i++) read(w[i]),ma[i][0]=w[i],pos1[i]=i; dep[1]=1;
        for (int i=2;i<=n;i++) {
          read(fa[i]),dep[i]=dep[fa[i]]+1; 
          f[i][0]=fa[i]; 
          for (int j=1;j<SI;j++) ma[i][j]=Max(ma[i][j-1],ma[f[i][j-1]][j-1]),f[i][j]=f[f[i][j-1]][j-1];
        }
        read(q);
        for (int i=1;i<=q;i++) {
          read(qu),read(que); 
          ans[i]=dep[que]-dep[qu]; pos2[i]=i;
          if (ans[i]<=1) continue;
          need[i]=1;
          p[i]=qu;
          val[i]=0; t=fa[que];
          for (int j=SI-1;~j;j--) 
            if (dep[f[t][j]]>=dep[qu]) 
             val[i]=Max(val[i],ma[t][j]),t=f[t][j];
        }
        for (int i=1;i<=n;i++) dep[i]--;
        sort(pos1+1,pos1+n+1,[&](int _x,int _y){return w[_x]>w[_y];});
        sort(pos2+1,pos2+q+1,[&](int _x,int _y){return val[_x]>val[_y];});
        for (int i=1;i<=q;i++)  if (need[pos2[i]]) {
            while (j<n&&w[pos1[j+1]]>val[pos2[i]])  
               add(pos1[++j]);
            ans[pos2[i]]-=query(p[pos2[i]],val[pos2[i]]);
        }
        while (j<n) add(pos1[++j]);
        for (int i=1;i<=q;i++) if (need[i]) ans[i]+=query(p[i],0)-(LL)val[i]*dep[p[i]];
        for (int i=1;i<=q;i++) writeln(ans[i]);
        return 0;
    }
  • 相关阅读:
    Retrofit 2使用要点梳理:小白进阶回忆录
    浅析Android动画(三),自定义Interpolator与TypeEvaluator
    浅析Android动画(二),属性动画高级实例探究
    浅析Android动画(一),View动画高级实例探究
    Retrofit 2使用要点梳理:浅析POST文件/表单上传
    AS历史代码记录,找回本地未提交代码
    注解基础篇:自定义Java Annotation
    注解提高篇:自定义注解处理器(APT)
    AndroidStudio快捷键大全
    VisualStudio2015常用快捷键
  • 原文地址:https://www.cnblogs.com/rrsb/p/9867233.html
Copyright © 2011-2022 走看看