BZOJ2157 旅遊 【樹剖 或 LCT】

題目

Ray 樂忠於旅遊,這次他來到了T 城。T 城是一個水上城市,一共有 N 個景點,有些景點之間會用一座橋連接。爲了方便遊客到達每個景點但又爲了節約成本,T 城的任意兩個景點之間有且只有一條路徑。換句話說, T 城中只有N − 1 座橋。Ray 發現,有些橋上可以看到美麗的景色,讓人心情愉悅,但有些橋狹窄泥濘,令人煩躁。於是,他給每座橋定義一個愉悅度w,也就是說,Ray 經過這座橋會增加w 的愉悅度,這或許是正的也可能是負的。有時,Ray 看待同一座橋的心情也會發生改變。現在,Ray 想讓你幫他計算從u 景點到v 景點能獲得的總愉悅度。有時,他還想知道某段路上最美麗的橋所提供的最大愉悅度,或是某段路上最糟糕的一座橋提供的最低愉悅度。

輸入格式

輸入的第一行包含一個整數N,表示T 城中的景點個數。景點編號爲 0…N − 1。接下來N − 1 行,每行三個整數u、v 和w,表示有一條u 到v,使 Ray 愉悅度增加w 的橋。橋的編號爲1…N − 1。|w| <= 1000。輸入的第N + 1 行包含一個整數M,表示Ray 的操作數目。接下來有M 行,每行描述了一個操作,操作有如下五種形式: C i w,表示Ray 對於經過第i 座橋的愉悅度變成了w。 N u v,表示Ray 對於經過景點u 到v 的路徑上的每一座橋的愉悅度都變成原來的相反數。 SUM u v,表示詢問從景點u 到v 所獲得的總愉悅度。 MAX u v,表示詢問從景點u 到v 的路徑上的所有橋中某一座橋所提供的最大愉悅度。 MIN u v,表示詢問從景點u 到v 的路徑上的所有橋中某一座橋所提供的最小愉悅度。測試數據保證,任意時刻,Ray 對於經過每一座橋的愉悅度的絕對值小於等於1000。

輸出格式

對於每一個詢問(操作S、MAX 和MIN),輸出答案。

輸入樣例

3

0 1 1

1 2 2

8

SUM 0 2

MAX 0 2

N 0 1

SUM 0 2

MIN 0 2

C 1 3

SUM 0 2

MAX 0 2

輸出樣例

3

2

1

-1

5

3

提示

一共有10 個數據,對於第i (1 <= i <= 10) 個數據, N = M = i * 2000。

題解

憑着對樹剖的熟練度,20min打完180+行直接1A【只會打板
學了LCT發現其實樹剖的題目都可以用LCT刷刷
LCT明天補上【如果我查得完錯
UPDATE:已補LCT
果然樹剖快挺多
這裏寫圖片描述

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 20005,maxm = 100005,INF = 1000000000;
inline int RD(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
    return out * flag;
}
char opt[10];
int h[maxn],ne = 0,N,M;
struct EDGE{int to,nxt,w,i;}ed[maxm];
inline void build(int u,int v,int w,int i){
    ed[ne] = (EDGE){v,h[u],w,i}; h[u] = ne++;
    ed[ne] = (EDGE){u,h[v],w,i}; h[v] = ne++;
}
int fa[maxn],dep[maxn],son[maxn],V[maxn],id[maxn],P[maxn],H[maxn],top[maxn],siz[maxn];
int cnt = 0;
void dfs1(int u){
    siz[u] = 1; int to;
    Redge(u) if ((to = ed[k].to) != fa[u]){
        dep[to] = dep[u] + 1; fa[to] = u; P[ed[k].i] = to; V[to] = ed[k].w;
        dfs1(to);
        siz[u] += siz[to];
        if (!son[u] || siz[to] > siz[son[u]]) son[u] = to;
    }
}
void dfs2(int u,int flag){
    id[u] = ++cnt; H[cnt] = u; top[u] = flag ? top[fa[u]] : u; int to;
    if (son[u]) dfs2(son[u],true);
    Redge(u) if ((to = ed[k].to) != fa[u] && to != son[u]) dfs2(to,false);
}
int sum[4 * maxn],mx[4 * maxn],mn[4 * maxn],tag[4 * maxn],L,R;
void pup(int u){
    sum[u] = sum[ls] + sum[rs];
    mx[u] = max(mx[ls],mx[rs]);
    mn[u] = min(mn[ls],mn[rs]);
}
void pd(int u){
    if (tag[u]){
        sum[ls] = -sum[ls]; sum[rs] = -sum[rs];
        swap(mx[ls],mn[ls]); mx[ls] = -mx[ls]; mn[ls] = -mn[ls];
        swap(mx[rs],mn[rs]); mx[rs] = -mx[rs]; mn[rs] = -mn[rs];
        tag[ls] ^= 1; tag[rs] ^= 1; tag[u] ^=1;
    }
}
void build(int u,int l,int r){
    if (l == r){
        sum[u] = mx[u] = mn[u] = V[H[l]];
        return;
    }
    int mid = l + r >> 1;
    build(ls,l,mid);
    build(rs,mid + 1,r);
    pup(u);
}
void modify(int u,int l,int r,int v){
    if (l == r) {sum[u] = mx[u] = mn[u] = v; return;}
    pd(u);
    int mid = l + r >> 1;
    if (mid >= L) modify(ls,l,mid,v);
    else modify(rs,mid + 1,r,v);
    pup(u);
}
void rever(int u,int l,int r){
    if (l >= L && r <= R){
        sum[u] = -sum[u];
        swap(mx[u],mn[u]); mx[u] = -mx[u]; mn[u] = -mn[u];
        tag[u] ^= 1;
        return;
    }
    pd(u);
    int mid = l + r >> 1;
    if (mid >= L) rever(ls,l,mid);
    if (mid < R) rever(rs,mid + 1,r);
    pup(u);
}
int Query(int u,int l,int r){
    if (l >= L && r <= R) return sum[u];
    pd(u);
    int mid = l + r >> 1;
    if (mid >= R) return Query(ls,l,mid);
    else if (mid < L) return Query(rs,mid + 1,r);
    else return Query(ls,l,mid) + Query(rs,mid + 1,r);
}
int Qmin(int u,int l,int r){
    if (l >= L && r <= R) return mn[u];
    pd(u);
    int mid = l + r >> 1;
    if (mid >= R) return Qmin(ls,l,mid);
    else if (mid < L) return Qmin(rs,mid + 1,r);
    else return min(Qmin(ls,l,mid),Qmin(rs,mid + 1,r));
}
int Qmax(int u,int l,int r){
    if (l >= L && r <= R) return mx[u];
    pd(u);
    int mid = l + r >> 1;
    if (mid >= R) return Qmax(ls,l,mid);
    else if (mid < L) return Qmax(rs,mid + 1,r);
    else return max(Qmax(ls,l,mid),Qmax(rs,mid + 1,r));
}
void solve1(){
    int u = P[RD()],w = RD();
    L = id[u]; modify(1,1,N,w);
}
void solve2(){
    int u = RD() + 1,v = RD() + 1;
    while (top[u] != top[v]){
        if (dep[top[u]] < dep[top[v]]) swap(u,v);
        L = id[top[u]]; R = id[u];
        rever(1,1,N);
        u = fa[top[u]];
    }
    if (u == v) return;
    if (dep[u] > dep[v]) swap(u,v);
    L = id[u] + 1; R = id[v];
    rever(1,1,N);
}
void solve3(){
    int u = RD() + 1,v = RD() + 1,ans = 0;
    while (top[u] != top[v]){
        if (dep[top[u]] < dep[top[v]]) swap(u,v);
        L = id[top[u]]; R = id[u];
        ans += Query(1,1,N);
        u = fa[top[u]];
    }
    if (u != v){
        if (dep[u] > dep[v]) swap(u,v);
        L = id[u] + 1; R = id[v];
        ans += Query(1,1,N);
    }
    printf("%d\n",ans);
}
void solve4(){
    int u = RD() + 1,v = RD() + 1,ans = -INF;
    while (top[u] != top[v]){
        if (dep[top[u]] < dep[top[v]]) swap(u,v);
        L = id[top[u]]; R = id[u];
        ans = max(ans,Qmax(1,1,N));
        u = fa[top[u]];
    }
    if (u != v){
        if (dep[u] > dep[v]) swap(u,v);
        L = id[u] + 1; R = id[v];
        ans = max(ans,Qmax(1,1,N));
    }
    printf("%d\n",ans);
}
void solve5(){
    int u = RD() + 1,v = RD() + 1,ans = INF;
    while (top[u] != top[v]){
        if (dep[top[u]] < dep[top[v]]) swap(u,v);
        L = id[top[u]]; R = id[u];
        ans = min(ans,Qmin(1,1,N));
        u = fa[top[u]];
    }
    if (u != v){
        if (dep[u] > dep[v]) swap(u,v);
        L = id[u] + 1; R = id[v];
        ans = min(ans,Qmin(1,1,N));
    }
    printf("%d\n",ans);
}
int main(){
    memset(h,-1,sizeof(h));
    N = RD(); int u,v,w;
    REP(i,N - 1) u = RD() + 1,v = RD() + 1,w = RD(),build(u,v,w,i);
    dep[1] = 1; dfs1(1); dfs2(1,0); build(1,1,N);
    M = RD();
    while (M--){
        scanf("%s",opt);
        if (opt[0] == 'C') solve1();
        else if (opt[0] == 'N') solve2();
        else if (opt[0] == 'S') solve3();
        else if (opt[1] == 'A') solve4();
        else solve5();
    }
    return 0;
}

LCT:【代碼短但會慢一點】

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define isrt(u) (!f[u] || (ch[f[u]][0] != u && ch[f[u]][1] != u))
#define isr(u) (ch[f[u]][1] == u)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
#define ls (ch[u][0])
#define rs (ch[u][1])
using namespace std;
const int maxn = 40005,maxm = 100005,INF = 1000000000;
inline int RD(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
    return out * flag;
}
int rev[maxn],Min[maxn],Max[maxn],f[maxn],ch[maxn][2],sum[maxn];
int tag[maxn],V[maxn],N,M,ed[maxn];
char opt[10];
void Rever(int u){
    swap(Min[u],Max[u]); Max[u] = -Max[u]; Min[u] = -Min[u];
    sum[u] = -sum[u]; V[u] = -V[u];
    tag[u] ^= 1;
}
void pup(int u){
    Max[u] = max(Max[ls],Max[rs]);
    Min[u] = min(Min[ls],Min[rs]);
    if (u > N) Max[u] = max(Max[u],V[u]);
    if (u > N) Min[u] = min(Min[u],V[u]);
    sum[u] = sum[ls] + sum[rs] + V[u];
}
void pd(int u){
    if (rev[u]){swap(ls,rs); rev[ls] ^= 1; rev[rs] ^= 1; rev[u] ^= 1;}
    if (tag[u]){
        if (ls) Rever(ls);
        if (rs) Rever(rs);
        tag[u] = 0;
    }
}
void push_down(int u){
    if (!isrt(u)) push_down(f[u]);
    pd(u);
}
void spin(int u){
    int s = isr(u),fa = f[u];
    f[u] = f[fa]; if (!isrt(fa)) ch[f[fa]][isr(fa)] = u;
    ch[fa][s] = ch[u][s ^ 1]; if (ch[u][s ^ 1]) f[ch[u][s ^ 1]] = fa;
    f[fa] = u; ch[u][s ^ 1] = fa;
    pup(fa); pup(u);
}
void splay(int u){
    for (push_down(u); !isrt(u); spin(u))
        if (!isrt(f[u])) spin((isr(u) ^ isr(f[u])) ? u : f[u]);
}
void Access(int u){
    for (int v = 0; u; u = f[v = u])
        splay(u),ch[u][1] = v,pup(u);
}
void Make_rt(int u){
    Access(u); splay(u); rev[u] ^= 1;
}
void Split(int u,int v){
    Make_rt(u); Access(v); splay(v);
}
void Link(int u,int v){
    Make_rt(u); f[u] = v;
}
void solve1(){
    int u = ed[RD()],v = RD();
    splay(u); V[u] = v; pup(u);
}
void solve2(){
    int u = RD() + 1,v = RD() + 1;
    Split(u,v); Rever(v);
}
void solve3(){
    int u = RD() + 1,v = RD() + 1;
    Split(u,v);
    printf("%d\n",sum[v]);
}
void solve4(){
    int u = RD() + 1,v = RD() + 1;
    Split(u,v);
    printf("%d\n",Max[v]);
}
void solve5(){
    int u = RD() + 1,v = RD() + 1;
    Split(u,v);
    printf("%d\n",Min[v]);
}
int main(){
    N = RD();
    int u,v,w,id = N;
    for (int i = 0; i <= N; i++) Max[i] = -INF,Min[i] = INF;
    REP(i,N - 1){
        u = RD() + 1,v = RD() + 1,w = RD();
        ed[i] = ++id; V[id] = Max[id] = Min[id] = sum[id] = w;
        Link(u,id); Link(v,id);
    }
    M = RD();
    while (M--){
        scanf("%s",opt);
        if (opt[0] == 'C') solve1();
        else if (opt[0] == 'N') solve2();
        else if (opt[0] == 'S') solve3();
        else if (opt[1] == 'A') solve4();
        else solve5();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章