[NOIP2018]保卫王国

[Luogu5024]

感谢包爷的帮助

细节详见代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
#define int long long
using namespace std;
typedef long long LL;
const LL INF=1e16+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int N=1e5+5;
const int M=2e5+5;

struct Edge{
    int v,nxt;
}e[M];
int first[N],Ecnt=0;
inline void Add_edge(int u,int v){
    e[++Ecnt]=(Edge){v,first[u]};
    first[u]=Ecnt;
}

int a[N];LL dp[N][2];

struct Matrix{
    LL a[2][2];
    Matrix (){a[0][0]=a[0][1]=a[1][0]=a[1][1]=INF;}//初始化
    inline LL* operator [](int x){return a[x];}
    inline friend Matrix operator * (Matrix a,Matrix b){
        Matrix res;
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++)
                for(int k=0;k<2;k++)
                    res[i][j]=min(res[i][j],a[i][k]+b[k][j]);
        }
        return res;
    }
}g[N],f[N];

namespace LCT{
    int par[N],ch[N][2];
#define ls (ch[x][0])
#define rs (ch[x][1])
    inline bool chk(int x){
        return ch[par[x]][1]==x;
    }
    inline bool nrt(int x){
        return ch[par[x]][0]==x||ch[par[x]][1]==x;
    }
    inline void pushup(int x){
        f[x]=g[x];//虚儿子由于是轻边,一定是要f[rs]*g[x]*f[ls],从下往上更新也符合dp思路
        if(rs) f[x]=f[rs]*f[x];
        if(ls) f[x]=f[x]*f[ls];
    }
    inline void rotate(int x){
        int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
        ch[y][k]=w,par[w]=y;
        if(nrt(y)) ch[z][chk(y)]=x; par[x]=z;
        ch[x][k^1]=y,par[y]=x;
        pushup(y);pushup(x);
    }
    inline void splay(int x){
        while(nrt(x)){
            int y=par[x];
            if(nrt(y)){
                if(chk(x)==chk(y)) rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
    }
    inline void access(int x){
        for(int y=0;x;x=par[y=x]){
            splay(x);
            if(rs){
                g[x][0][1]+=min(f[rs][1][0],f[rs][1][1]);//rs变为虚边
                g[x][1][1]+=min(f[rs][1][0],f[rs][1][1]);
                g[x][1][0]+=f[rs][1][1];
            }
            if(y){
                g[x][0][1]-=min(f[y][1][0],f[y][1][1]);//y变为实边
                g[x][1][1]-=min(f[y][1][0],f[y][1][1]);
                g[x][1][0]-=f[y][1][1];
            }
            rs=y;
            pushup(x);
        }
    }
    inline void modify(int x,int val){
        access(x);splay(x);
        g[x][0][1]+=val-a[x];
        g[x][1][1]+=val-a[x];
        pushup(x);
        a[x]=val;// x[a]==a[x]
    }
#undef ls
#undef rs
}using namespace LCT;

inline void dfs(int u,int pre){
    dp[u][1]=a[u];
    par[u]=pre;
    for(int i=first[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==pre) continue;
        dfs(v,u);
        dp[u][1]+=min(dp[v][0],dp[v][1]);
        dp[u][0]+=dp[v][1];
    }
    f[u][0][1]=f[u][1][1]=dp[u][1];
    f[u][1][0]=dp[u][0];
    g[u]=f[u];//一开始全是虚子树
}

signed main(){
    int n=read(),m=read();char op[10];scanf("%s",op);
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n-1;i++){
        int x=read(),y=read();
        Add_edge(x,y);
        Add_edge(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++){
        int aa=read(),x=read(),bb=read(),y=read();
        int va=a[aa],vb=a[bb];

        if(x) modify(aa,0);//强制选:赋为0才能保证能选到
        else modify(aa,va+INF);
        if(y) modify(bb,0);
        else modify(bb,vb+INF);

        splay(1);
        LL ans=min(f[1][1][0],f[1][1][1]);

        if(ans>=INF) puts("-1");
        else{
            if(x) ans+=va;//然后又加上这个点的答案
            if(y) ans+=vb;
            printf("%lld\n",ans);
        }

        modify(aa,va);modify(bb,vb);//又改回去
    }
}
上一篇:Visual Studio 2017 和 VA番茄助手 安装教程


下一篇:模板 - 主席树