zoukankan      html  css  js  c++  java
  • [ZJOI2018]历史

    [ZJOI2018]历史 

    最大化access轻重链的切换次数

    考虑一个点的贡献,即它交换重儿子的次数

    发现这个次数只和它自己ai以及每个儿子的子树次数和有关。

    一个关键的事实是:

    我们可以自上而下进行贪心!

    我们最大化fa的贡献,发现,对于操作序列,一个儿子子树的操作是一个子序列,不影响这个儿子子树的贡献!

    (内部可以任意交换)

    等价于:有m=|son|+1种颜色,每种颜色有若干个

    排成一列,最大化相邻不相同颜色的次数

    设颜色最多的是h,总和为t

    则次数=min(t-1,2*(t-h))

    证明的话:考虑先放那最多的h个然后插空,对于剩下的p=(t-h)个,如果p<=h-1,那么显然直接插空,贡献2*p个,如果p>h-1,那么一定可以不断来回插空,达到上界t-1

    已经可以做不修改的了。

    修改:

    关键:1.只加w。2.考虑临界情况:2*h>=t+1时候,贡献2*(t-h),否则贡献t-1。3.仅影响到根的链答案

    如果一个点可以作为fa的最大值来源,则把这个链变成实链。

    发现,修改一个点x时候,往上跳,实链还是实链,并且贡献还是不变的!

    所以,只用考虑虚边的影响

    发现,每跳一个虚边,所在子树的S*=2,所以最多log∑ai个

    修改虚边:

    减去原来的贡献,加上新来的贡献,分类讨论

    用LCT的access实现跳跃实链

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=4e5+5;
    int n,m;
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    ll ans;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    struct tr{
        int ch[2],fa;
        ll v,s,si;
        void out(){
            cout<<" ch0 "<<ch[0]<<" ch1 "<<ch[1]<<" fa "<<fa<<endl;
            cout<<" v "<<v<<" s "<<s<<" si "<<si<<endl;
        }
    }t[N];
    #define ls t[x].ch[0]
    #define rs t[x].ch[1]
    bool nrt(int x){
        return t[t[x].fa].ch[0]==x||(t[t[x].fa].ch[1]==x);
    }
    void pushup(int x){
        if(x) t[x].s=t[ls].s+t[rs].s+t[x].si+t[x].v;
    }
    void rotate(int x){
        int y=t[x].fa,d=t[y].ch[1]==x;
        t[t[y].ch[d]=t[x].ch[!d]].fa=y;
        if(nrt(y)) t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[1]==y]=x;
        else t[x].fa=t[y].fa;
        t[t[x].ch[!d]=y].fa=x;
        pushup(y);
    }
    void splay(int x){
        while(nrt(x)){
            int y=t[x].fa,z=t[y].fa;
            if(nrt(y)){
                rotate((t[y].ch[0]==x)==(t[z].ch[0]==y)?y:x);
            }
            rotate(x);
        }
        pushup(x);
    }
    void dfs(int x,int fa){
        ll mx=t[x].v;t[x].s=t[x].v;
        int p=x;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            t[y].fa=x;
            dfs(y,x);
            t[x].s+=t[y].s;
            t[x].si+=t[y].s;
            if(t[y].s>mx){
                mx=t[y].s;p=y;
            }
        }
        if(2*mx>=t[x].s+1){
            if(p!=x) {
                rs=p;t[x].si-=t[p].s;
            }
        }
        ans+=min(t[x].s-1,2*(t[x].s-mx));
    }
    
    int main(){
        int m;
        rd(n);rd(m);
        for(reg i=1;i<=n;++i){
            rd(t[i].v);
        }
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);
            add(x,y);add(y,x);
        }
        dfs(1,0);
        printf("%lld
    ",ans);
        ll w;
        // for(reg i=1;i<=n;++i){
        //     cout<<i<<" : ";t[i].out();
        // }cout<<endl;
    
    
        while(m--){
            rd(x);rd(w);
            for(reg y=0;x;y=x,x=t[x].fa){
                splay(x);
                ll S=t[x].s-t[ls].s;
                // cout<<" x "<<x<<" y "<<y<<" S "<<S<<endl;
                ll con=rs?min(S-1,2*(S-t[rs].s)):min(S-1,2*(S-t[x].v));
                // cout<<" con "<<con<<endl;
                ans-=con;
                if(!y) {
                    t[x].v+=w;S+=w;t[x].s+=w;
                }else{
                    t[x].si+=w;S+=w;t[x].s+=w;
                }
                // cout<<" out ";t[x].out();
                if(y){
                    if(rs){
                        if(2*t[rs].s<S+1&&2*t[y].s<S+1){
                            ans+=S-1;
                            t[x].si+=t[rs].s;
                            rs=0;
                        }else if(2*t[rs].s>2*t[y].s){
                            ans+=2*(S-t[rs].s);
                        }else{
                            ans+=2*(S-t[y].s);
                            t[x].si+=t[rs].s;
                            t[x].si-=t[y].s;
                            rs=y;
                        }
                    }else{
                        if(2*t[x].v<S+1&&2*t[y].s<S+1){
                            ans+=S-1;
                        }else if(2*t[x].v>2*t[y].s){
                            ans+=2*(S-t[x].v);
                        }else{
                            ans+=2*(S-t[y].s);
                            t[x].si-=t[y].s;
                            rs=y;
                        }
                    }
                }else{
                    if(rs){
                        if(2*t[rs].s<S+1&&2*t[x].v<S+1){
                            ans+=S-1;
                            t[x].si+=t[rs].s;
                            rs=0;
                        }else if(2*t[rs].s>2*t[x].v){
                            ans+=2*(S-t[rs].s);
                        }else{
                            ans+=2*(S-t[x].v);
                            t[x].si+=t[rs].s;
                            rs=0;
                        }
                    }else{
                        if(2*t[x].v<S+1&&2*t[y].s<S+1){
                            ans+=S-1;
                        }else if(2*t[x].v>2*t[y].s){
                            ans+=2*(S-t[x].v);
                        }else{
                            ans+=2*(S-t[y].s);
                            t[x].si-=t[y].s;
                            rs=y;
                        }
                    }
                }
                pushup(x);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/4/13 19:58:12
    */

    1.考虑每个点的贡献!把题意进行转化

    2.修改时候,考虑具体影响的部分是哪些。

  • 相关阅读:
    objectiveC中的序列化(serialize)与反序列化(deserialize)
    objectiveC 的代码文件组织
    [转载]Multicast Explained in Flash 10.1 P2P
    几种异步操作方式
    objectiveC 的内存管理之自动释放池(autorelease pool)
    用VS2010调试微软开放的部分源码
    浏览器窗口尺寸改变时的图片自动重新定位
    数据结构C#版笔记啥夫曼树(Huffman Tree)与啥夫曼编码(Huffman Encoding)
    objectiveC 的内存管理之实例分析
    objectiveC 的OOP(上)类定义、继承及方法调用
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10744104.html
Copyright © 2011-2022 走看看