水题求助

P4114 Qtree1

CultReborn @ 2023-11-15 11:24:41

WA 0pts

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 100005;
inline LL Read();void Rite(LL x);
int a[maxn],c[maxn],n;
int head[maxn],cnt(-1);
int fth[maxn],dep[maxn],dfn[maxn];
int siz[maxn],son[maxn],top[maxn];
int ti = 0;
struct node{
    int u,to,nxt,cst;
}edge[maxn * 2];
struct SegmentTree{
    int left,right;
    LL data;
#define l(p) t[p].left
#define r(p) t[p].right
#define d(p) t[p].data
}t[maxn * 4];
void Input(int u,int v,int w){
    edge[++cnt] = {u,v,head[u],w};
    head[u] = cnt;
}
void DFS1(int u,int fa){
    dep[u] = dep[fa] + 1;
    siz[u] = 1;
    fth[u] = fa;
    for(int i = head[u];~i;i = edge[i].nxt){
        int v = edge[i].to;
        if(v == fa) continue;
        c[v] = edge[i].cst;
        DFS1(v,u);
        siz[u] += siz[v];
        if(!son[u] || siz[son[u]] < siz[v])
            son[u] = v;
    }
}
void DFS2(int u,int tp){
    dfn[u] = ++ti;
    a[ti] = c[u];
    top[u] = tp;
    if(!son[u]) return;
    DFS2(son[u],tp);
    for(int i = head[u];~i;i = edge[i].nxt){
        int v = edge[i].to;
        if(son[u] != v && fth[u] != v)
            DFS2(v,v);
    }
}
void Build(int p,int l,int r){
    l(p) = l; r(p) = r;
    if(l == r){d(p) = a[l];return;}
    int mid = (l + r) / 2;
    Build(p * 2,l,mid);
    Build(p*2+1,mid + 1,r);
    d(p) = max(d(p * 2),d(p*2+1));
}
void Change(int p,int l,LL d){
    if(l(p) == r(p)){d(p) = max(d,d(p));return;}
    int mid = (l(p) + r(p)) / 2;
    if(l <= mid) Change(p * 2,l,d);
    else Change(p*2+1,l,d);
    d(p) = max(d(p * 2),d(p*2+1));
}
LL Ask(int p,int l,int r){
    if(l <= l(p) && r >= r(p))
        return d(p);
    LL ans(INT_MIN);
    int mid = (l(p) + r(p)) / 2;
    if(l <= mid) ans = max(ans,Ask(p * 2,l,r));
    if(r > mid)  ans = max(ans,Ask(p*2+1,l,r));
    return ans;
}
LL Query(int u,int v){
    if(u == v) return 0;
    LL ans(0);
    while(top[u] != top[v]){
        if(dep[top[u]] < dep[top[v]]) swap(u,v);
        ans = max(ans,Ask(1,dfn[top[u]],dfn[u]));
        u = fth[top[u]];
    }
    if(dep[u] > dep[v]) swap(u,v);
    ans = max(ans,Ask(1,dfn[u] + 1,dfn[v]));
    return ans;
}
int main(){
    n = Read();
    memset(head,-1,sizeof(head));
    for(int i = 1;i <= n - 1;++i){
        int u(Read()),v(Read()),w(Read());
        Input(u,v,w); Input(v,u,w);
    }
    DFS1(1,0); DFS2(1,1); Build(1,1,n);
    while(1){
        string s; cin >> s;
        if(s[0] == 'D') break;
        int x(Read()),y(Read());
        if(s[0] == 'C'){
            x = (x - 1) * 2;
            int u(edge[x].u),v(edge[x].to);
            if(fth[v] == u) swap(u,v);
            Change(1,dfn[u],y);
        }
        else Rite(Query(x,y)),putchar('\n');
    }
    return 0;
}
inline LL Read(){
    char c = getchar();
    LL x = 0,f = 1;
    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}void Rite(LL x){
    if(x < 0) putchar('-'),x = -x;
    if(x > 9) Rite(x / 10);
    putchar(x % 10 + '0');
}

by ATZdhjeb @ 2023-11-15 11:35:34

hack:

5
1 2 1
1 4 1
2 3 1
4 5 1
QUERY 1 5
CHANGE 2 2
QUERY 1 5
DONE

by ATZdhjeb @ 2023-11-15 11:36:20

查询的时候要考虑两个点跳到一起的情况


by CultReborn @ 2023-11-15 12:57:46

@ATZdhjeb 十分感谢,十分感谢


by CultReborn @ 2023-11-15 13:05:43

@ATZdhjeb 但是好像两个点不可能跳到一起啊


by CultReborn @ 2023-11-15 13:07:49

我的代码也输出了

1

2

似乎没有问题


by ATZdhjeb @ 2023-11-15 13:12:23

@CultReborn 啊??

我本地跑你的代码输出两个 1(


by ATZdhjeb @ 2023-11-15 13:15:03

就,从理论上分析,它是把边权传到儿子节点上,然后两个点的 LCA 的值存的是 LCA 到 LCA 父亲的边权,所以不能算进去才对。

然后现在看一下好像我的 hack 也有点问题,等我再想想(


by CultReborn @ 2023-11-15 13:17:18

@ATZdhjeb 78行的

while(top[u] != top[v])

规避了两个点跳到一起的情况,我这边确实是 1 2。

已关注,感谢感谢!


by ATZdhjeb @ 2023-11-15 13:27:51

@CultReborn 好好好,你是线段树修改错了,直接赋值,不是取 max。查询确实没错。

以及为什么最近我一水贴就成小丑,这下发现自己树剖也没学懂了。


by CultReborn @ 2023-11-15 13:37:00

@ATZdhjeb 以及为什么最近我一水贴就小丑,这下发现自己线段树也没学懂了。


|