弱校联盟国庆第二天 D题

据说是一道很裸的树链剖分,但是我感觉树链剖分并不是很好写。。。然后就行LCT写了,很裸的LCT,但是这道题居然RE, dfs爆栈了,然后我把vector存边换成结构体居然就过了!!!大家好像是dfs的时候把根换点就能过了。
本题题意:有两个操作,1:把u->v的链上的点全部变成w。2:找出u->v这条链上最大非空区间和,这个就是把左右两段合起来。
附上ac代码:

#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <vector>
#define LL long long
#define INF 0x3fffffff
#define FOR(i,x,y)  for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define MAXN 440000

using namespace std;

int n,m;

int head[MAXN],edge_cnt;

struct Edge{
    int u,v;
    int nt;
}edge[MAXN<<1];

void add_edge(int u,int v){
    edge[edge_cnt].u = u;
    edge[edge_cnt].v = v;
    edge[edge_cnt].nt = head[u];
    head[u] = edge_cnt++;
}

struct LCT{
    int pre[MAXN],ch[MAXN][2],flip[MAXN];
    int key[MAXN];
    int ans[MAXN],l[MAXN],r[MAXN],sum[MAXN],lazy[MAXN],sz[MAXN];
    bool mk[MAXN];
    bool rt[MAXN];

    void Update_Lazy(int x,int w){
        if(!x)  return;
        lazy[x] = w;
        key[x] = w;
        sum[x] = sz[x] * w;
        ans[x] = w>0 ? (sz[x]*w) : w;
        l[x] = ans[x];
        r[x] = ans[x];
        mk[x] = true;
    }

    void Update_Flip(int x){
        if(!x)  return;
        swap(l[x],r[x]);
        swap(ch[x][0],ch[x][1]);
        flip[x] ^= 1;
    }

    void Init(){
        memset(ch,0,sizeof(ch));
        memset(flip,0,sizeof(flip));
        memset(rt,true,sizeof(rt));
        memset(mk,false,sizeof(mk));
        memset(lazy,-1,sizeof(lazy));
        sz[0] = sum[0] = key[0] = l[0] = r[0] = ans[0] = 0;
        FOR(i,1,n+1){
            ans[i] = sum[i] = l[i] = r[i] = key[i];
            sz[i] = 1;
        }
    }

    void PushUp(int x){
        sz[x] = 1 + sz[ch[x][0]] + sz[ch[x][1]];
        sum[x] = key[x] + sum[ch[x][0]] + sum[ch[x][1]];
        if(ch[x][0]){
            l[x] = max(max(l[ch[x][0]],sum[ch[x][0]]+key[x]),sum[ch[x][0]]+key[x]+l[ch[x][1]]);
        }
        else
            l[x] = max(key[x],key[x]+l[ch[x][1]]);
        if(ch[x][1]){
            r[x] = max(max(r[ch[x][1]],sum[ch[x][1]]+key[x]),sum[ch[x][1]]+key[x]+r[ch[x][0]]);
        }
        else
            r[x] = max(key[x],key[x]+r[ch[x][0]]);
        int t = key[x] + (l[ch[x][1]] > 0 ? l[ch[x][1]] : 0) + (r[ch[x][0]] > 0 ? r[ch[x][0]] : 0);
        if(ch[x][0] && ch[x][1]){
            ans[x] = max(max(ans[ch[x][0]],ans[ch[x][1]]),t);
        }
        else if(ch[x][0]){
            ans[x] = max(ans[ch[x][0]],t);
        }
        else if(ch[x][1]){
            ans[x] = max(ans[ch[x][1]],t);
        }
        else ans[x] = t;
    }

    void PushDown(int x){
        if(mk[x]){
            Update_Lazy(ch[x][0],lazy[x]);
            Update_Lazy(ch[x][1],lazy[x]);
            mk[x] = false;
        }
        if(flip[x]){
            Update_Flip(ch[x][0]);
            Update_Flip(ch[x][1]);
            flip[x] = 0;
        }
    }

    void Rotate(int x,int kind){
        int y = pre[x];
        PushDown(y);
        PushDown(x);
        ch[y][!kind] = ch[x][kind];
        if(ch[x][kind]) pre[ch[x][kind]] = y;
        if(rt[y]){
            rt[x] = true;
            rt[y] = false;
        }
        else{
            if(ch[pre[y]][1] == y)  ch[pre[y]][1] = x;
            if(ch[pre[y]][0] == y)  ch[pre[y]][0] = x;
        }
        pre[x] = pre[y];
        pre[y] = x;
        ch[x][kind] = y;
        PushUp(y);
    }

    void Splay(int x){
        PushDown(x);
        while(!rt[x]){
            int y = pre[x];
            int z = pre[y];
            if(rt[y]){
                PushDown(y); PushDown(x);
                Rotate(x,ch[y][0] == x);
            }
            else{
                PushDown(z); PushDown(y); PushDown(x);
                int kind = ch[z][0] == y;
                if(ch[y][kind] == x){
                    Rotate(x,!kind);
                    Rotate(x,kind);
                }
                else{
                    Rotate(y,kind);
                    Rotate(x,kind);
                }
            }
        }
        PushUp(x);
    }

    void Access(int x){
        int fa = 0;
        for(;x;x = pre[fa = x]){
            Splay(x);
            rt[ch[x][1]] = true;
            rt[ch[x][1] = fa] = false;
            PushUp(x);
        }
    }

    int GetRoot(int x){
        Access(x);
        Splay(x);
        while(ch[x][0]) x = ch[x][0];
        return x;
    }

    void MakeRoot(int x){
        Access(x);
        Splay(x);
        Update_Flip(x);
    }

    void Modify(int u,int v,int w){
        MakeRoot(u);
        Access(v);
        Splay(v);
        Update_Lazy(v,w);
    }

    int Query(int u,int v){
        MakeRoot(u);
        Access(v);
        Splay(v);
        return ans[v];
    }

}lct;

void dfs(int u,int fa){
    lct.pre[u] = fa;
    for(int i = head[u];i != -1;i = edge[i].nt){
        int v = edge[i].v;
        if(v == fa) continue;
        dfs(v,u);
    }
}

int main(){
    //freopen("test.in","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        FOR(i,1,n+1)    scanf("%d",&lct.key[i]);
        edge_cnt = 0;
        memset(head,-1,sizeof(head));
        FOR(i,1,n){
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs(1,0);
        lct.Init();
        int op;
        int u,v;
        int w;
        FOR(i,0,m){
            scanf("%d",&op);
            if(op == 2){
                scanf("%d%d%d",&u,&v,&w);
                printf("%d\n",lct.Query(u,v));
            }
            else{
                scanf("%d%d%d",&u,&v,&w);
                lct.Modify(u,v,w);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值