• BZOJ5212 ZJOI2018历史(LCT)


      首先相当于最大化access的轻重边交换次数。

      考虑每个点作为战场(而不是每个点所代表的国家与其他国家交战)对答案的贡献,显然每次产生贡献都是该点的子树内(包括自身)此次access的点与上次access的点在该点不同儿子的子树内。假设得到了最后的崛起序列,可以发现相互不包含的子树的贡献是相互独立的,只是内部交换而不交换他们的相对顺序,对答案没有任何影响。

      那么现在只需要考虑最大化某点的贡献,显然应该让不同儿子的子树内的点尽量交替access。设各点子树的Σai为si,那么当不存在2sson>si时,该点贡献为si-1,否则为2(si-max{sson})。于是如果没有修改,对每个子树求出s就能计算答案了。

      接下来考虑怎么修改。显然修改某点会影响该点到根的路径上的所有点的贡献。因为贡献与2sson>si的儿子有特殊的关系,考虑将其视为preferred child,把子树根与该儿子的边设为重边,如果不存在或根自身就是最大的就与儿子全部连轻边。同时注意到修改只会使某点的ai增加,如果其本来就是preferred child,修改后仍然是,并且可以发现这不会对答案造成影响;如果不是的话可能会存在轻重边切换的情况,其自身变为preferred child,但无论如何这说明这棵子树原来的sson不足其父亲si的一半,而这显然只能存在log次。所以用一棵不会动的LCT做一个真正的access就能修改了,可以打个lazy避免维护子树。感觉有一堆情况事实上最后也没啥要讨论的。

      虽然写了一年但是1A感觉爽爆啊?

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    using namespace std;
    #define ll long long
    #define N 400010
    #define lson tree[k].ch[0]
    #define rson tree[k].ch[1]
    #define lself tree[tree[k].fa].ch[0]
    #define rself tree[tree[k].fa].ch[1]
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,p[N],t;
    ll ans;
    struct data{int to,nxt;
    }edge[N<<1];
    struct data2{int ch[2],fa;ll x,s,lazy,ans;
    }tree[N];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void dfs(int k,int from)
    {
        tree[k].s=tree[k].x;ll mx=tree[k].x;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from)
        {
            tree[edge[i].to].fa=k;
            dfs(edge[i].to,k);
            tree[k].s+=tree[edge[i].to].s;
            mx=max(mx,tree[edge[i].to].s);
        }
        if (2*mx<=tree[k].s) tree[k].ans=tree[k].s-1;
        else
        {
            tree[k].ans+=tree[k].s-mx<<1;
            for (int i=p[k];i;i=edge[i].nxt)
            if (edge[i].to!=from&&tree[edge[i].to].s==mx) {tree[k].ch[1]=edge[i].to;break;}
        }
        ans+=tree[k].ans;
    }
    void add(int k,ll x){if (k) tree[k].s+=x,tree[k].lazy+=x;}
    void down(int k){if (tree[k].lazy) add(lson,tree[k].lazy),add(rson,tree[k].lazy),tree[k].lazy=0;}
    int whichson(int k){return rself==k;}
    bool isroot(int k){return lself!=k&&rself!=k;}
    void push(int k){if (!isroot(k)) push(tree[k].fa);down(k);}
    void move(int k)
    {
        int fa=tree[k].fa,gf=tree[fa].fa,p=whichson(k);
        if (!isroot(fa)) tree[gf].ch[whichson(fa)]=k;tree[k].fa=gf;
        tree[fa].ch[p]=tree[k].ch[!p],tree[tree[k].ch[!p]].fa=fa;
        tree[k].ch[!p]=fa,tree[fa].fa=k;
    }
    void splay(int k)
    {
        push(k);
        while (!isroot(k))
        {
            int fa=tree[k].fa;
            if (!isroot(fa))
                if (whichson(fa)^whichson(k)) move(k);
                else move(fa);
            move(k);
        }
    }
    void access(int k,int x)
    {
        tree[k].x+=x;
        for (int t=0;k;)
        {
            splay(k);
            if (rson)
            {
                int p=rson;for (;tree[p].ch[0];p=tree[p].ch[0]) down(p);
                splay(p);
                while (!isroot(k)) move(k);
            }
            tree[k].s+=x;
            ans-=tree[k].ans;
            if ((tree[rson].s<<1)<=tree[k].s) rson=0;
            if ((tree[t].s<<1)>tree[k].s) rson=t,tree[k].ans=tree[k].s-tree[t].s<<1;
            else if ((tree[k].x<<1)>tree[k].s) tree[k].ans=tree[k].s-tree[k].x<<1;
            else if ((tree[rson].s<<1)>tree[k].s) tree[k].ans=tree[k].s-tree[rson].s<<1;
            else tree[k].ans=tree[k].s-1;
            ans+=tree[k].ans;
            add(lson,x);
            for (;lson;k=lson) down(k);
            splay(k);
            t=k;k=tree[k].fa;
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5212.in","r",stdin);
        freopen("bzoj5212.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        for (int i=1;i<=n;i++) tree[i].x=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read();
            addedge(x,y),addedge(y,x);
        }
        dfs(1,1);cout<<ans<<endl; 
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            access(x,y);
            printf(LL,ans);
        }
        return 0;
    }
  • 相关阅读:
    NOIP2016 天天爱跑步 正解
    NOIP2016 换教室
    iOS开发-14款状态栏(StatusBar)开源软件
    iOS 优化方案浅析
    iOS应用程序多语言本地化解决方案
    iOS开发流程总结
    iOS开发者必备:四款后端服务工具
    iOS开发之加载、滑动翻阅大量图片优化解决方案
    iOS开发之──传感器使用
    iOS开发中的Html解析方法
  • 原文地址:https://www.cnblogs.com/Gloid/p/10091951.html
Copyright © 2020-2023  润新知