bzoj1984 月下“毛景树”

Description

毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个。 ? Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。 ? Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问: ? Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

Input

第一行一个正整数N。 接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。

Output

对于毛毛虫的每个询问操作,输出一个答案。

树链剖分+线段树维护 区间max,区间覆盖标记,区间增加量标记

#include<cstdio>
char buf[10000005],*ptr=buf-1;
inline int input(){
    int x=0,c=*++ptr,f=1;
    while(c>57||c<48){if(c==‘-‘)f=-1;c=*++ptr;}
    while(c>47&&c<58)x=x*10+c-48,c=*++ptr;
    return x*f;
}
inline int getop(){
    int c=*++ptr;
    while(c<33)c=*++ptr;
    return *++ptr;
}
const int N=100050;
int mx[N*2],a[N*2],lc[N*2],rc[N*2],p=0,n;
bool cov[N*2];
int es[N*2],enx[N*2],ev[N*2],e0[N],v0[N],ep=2;
int l,r,ans;
int fa[N],dep[N],son[N],sz[N],top[N],v[N],id[N],ei[N][2],idr[N],idp=1;
inline int max(int a,int b){return a>b?a:b;}
void dwn(int w){
    if(a[w]){
        if(lc[w]){
            a[lc[w]]+=a[w];
            mx[lc[w]]+=a[w];
            a[rc[w]]+=a[w];
            mx[rc[w]]+=a[w];
        }
        a[w]=0;
    }
    if(cov[w]){
        if(lc[w]){
            cov[lc[w]]=cov[rc[w]]=1;
            mx[lc[w]]=mx[rc[w]]=mx[w];
        }
        cov[w]=0;
    }
}
inline void up(int w){
    mx[w]=max(mx[lc[w]],mx[rc[w]]);
}
int build(int L,int R){
    int u=++p;
    if(L==R){
        mx[u]=v0[idr[L]];
        return u;
    }
    int M=L+R>>1;
    lc[u]=build(L,M);
    rc[u]=build(M+1,R);
    up(u);
    return u;
}
void getmax(int w,int L,int R){
    if(l<=L&&R<=r){
        ans=max(ans,mx[w]);
        return;
    }
    dwn(w);
    int M=L+R>>1;
    if(l<=M)getmax(lc[w],L,M);
    if(r>M)getmax(rc[w],M+1,R);
}
void chg(int w,int L,int R){
    if(l<=L&&R<=r){
        a[w]=0;
        cov[w]=1;
        mx[w]=ans;
        return;
    }
    dwn(w);
    int M=L+R>>1;
    if(l<=M)chg(lc[w],L,M);
    if(r>M)chg(rc[w],M+1,R);
    up(w);
}
void inc(int w,int L,int R){
    if(l<=L&&R<=r){
        if(!cov[w])a[w]+=ans;
        mx[w]+=ans;
        return;
    }
    dwn(w);
    int M=L+R>>1;
    if(l<=M)inc(lc[w],L,M);
    if(r>M)inc(rc[w],M+1,R);
    up(w);
}
void f1(int w,int pa){
    fa[w]=pa;
    dep[w]=dep[pa]+1;
    sz[w]=1;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u==pa)continue;
        v0[u]=ev[i];
        f1(u,w);
        sz[w]+=sz[u];
        if(sz[u]>sz[son[w]])son[w]=u;
    }
}
void f2(int w,int tp){
    top[w]=tp;
    idr[id[w]=idp++]=w;
    if(son[w])f2(son[w],tp);
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=fa[w]&&u!=son[w])f2(u,u);
    }
}
void qmax(int x,int y){
    ans=0;
    int a=top[x],b=top[y],c;
    while(a!=b){
        if(dep[a]<dep[b])c=a,a=b,b=c,c=x,x=y,y=c;
        l=id[a];r=id[x];
        getmax(1,1,n);
        x=fa[a];a=top[x];
    }
    if(dep[x]<dep[y])l=id[x]+1,r=id[y];
    else l=id[y]+1,r=id[x];
    if(l<=r)getmax(1,1,n);
    printf("%d\n",ans);
}
void add(int x,int y){
    int a=top[x],b=top[y],c;
    while(a!=b){
        if(dep[a]<dep[b])c=a,a=b,b=c,c=x,x=y,y=c;
        l=id[a];r=id[x];
        inc(1,1,n);
        x=fa[a];a=top[x];
    }
    if(dep[x]<dep[y])l=id[x]+1,r=id[y];
    else l=id[y]+1,r=id[x];
    if(l<=r)inc(1,1,n);
}
void change(int x,int y){
    int a=top[x],b=top[y],c;
    while(a!=b){
        if(dep[a]<dep[b])c=a,a=b,b=c,c=x,x=y,y=c;
        l=id[a];r=id[x];
        chg(1,1,n);
        x=fa[a];a=top[x];
    }
    if(dep[x]<dep[y])l=id[x]+1,r=id[y];
    else l=id[y]+1,r=id[x];
    if(l<=r)chg(1,1,n);
}
int main(){
    fread(buf,1,10000000,stdin);
    n=input();
    for(int i=1;i<n;i++){
        int a=input(),b=input(),c=input();
        es[ep]=b;enx[ep]=e0[a];ev[ep]=c;e0[a]=ep++;
        es[ep]=a;enx[ep]=e0[b];ev[ep]=c;e0[b]=ep++;
        ei[i][0]=a;
        ei[i][1]=b;
    }
    f1(1,0);f2(1,1);build(1,n);
    while(1){
        int op=getop();
        if(op==‘t‘)break;
        if(op==‘a‘){
            int a=input(),b=input();
            qmax(a,b);
        }else if(op==‘h‘){
            int a=input(),b=input();
            l=r=(dep[ei[a][0]]>dep[ei[a][1]]?id[ei[a][0]]:id[ei[a][1]]);
            ans=b;
            chg(1,1,n);
        }else if(op==‘d‘){
            int a=input(),b=input(),c=input();
            ans=c;
            add(a,b);
        }else{
            int a=input(),b=input(),c=input();
            ans=c;
            change(a,b);
        }
    }
    return 0;
}
时间: 2024-10-11 17:05:47

bzoj1984 月下“毛景树”的相关文章

[BZOJ1984] 月下“毛景树”|树链剖分|线段树

1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1088  Solved: 348[Submit][Status][Discuss] Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没

[BZOJ1984]月下“毛景树”解题报告|树链剖分

Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个. ? Cover u v w:将节点u与节点

【树链剖分】【分块】【最近公共祖先】【块状树】bzoj1984 月下“毛景树”

裸题,但是因为权在边上,所以要先把边权放到这条边的子节点上,然后进行链更新/查询的时候不能更新/查询其lca. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 100001 #define BN 320 #define INF 2147483647 int fa[N],dep[N],siz[N],son[N],Num[N],tot,top[N],a[N

【BZOJ1984】月下“毛景树” 树链剖分+线段树

[BZOJ1984]月下"毛景树" Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~~~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: ?

BZOJ 1984: 月下“毛景树”( 树链剖分 )

水水的树链剖分... 将边上的权值转到深度较大的点上 , 然后要注意这样做之后修改或者查询 u , v 转到同一条重链上时 ( 假设 u 深度小 ) , 不能把 u 的权值算上 , 因为是 u 和它的 fa 的边的权值 , 从 u 到 v 并没有经过这条边 线段树维护 3 个域 set , add , max . ---------------------------------------------------------------------------- #include<cstdio

P4315 月下“毛景树”

P4315 月下"毛景树" 题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: Change k w:将第k条

[luogu4315]月下“毛景树”

[luogu4315]月下"毛景树" luogu 联赛前复习一发树剖.不会告诉你WA了4发 #define ls x<<1,l,mid #define rs x<<1|1,mid+1,r #include<bits/stdc++.h> using namespace std; const int _=1e5+5; int re(){ int x=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){

【BZOJ】1984 月下“毛景树”

[算法]树链剖分+线段树 [题解]线段树的区间加值和区间覆盖操作不能同时存在,只能存在一个. 修改:从根节点跑到目标区域路上的标记全部下传,打完标记再上传回根节点(有变动才需要上传). 询问:访问到目标区域路上的标记全部下传. 我写的线段树版本是在打标记的同时便对该点的询问项(最大值)做了对应更改,即可保证访问到该点得到的ms就是该点的答案. 访问某点时如果要询问最大值就直接拿走,如果要还要访问该点的子节点就需要下传. 而修改了某点的值,它的祖先的值就都需要变动,所以一旦修改必须上传至顶. 对于

[luogu]月下“毛景树”:树 剖 好 题

原题 题意: 给一棵树 , 每一条边都有边权 , 支持四种操作 1. 将第k条边权值修改为k 2. 将节点u到v的边权都覆盖为k 3. 将节点u到v的边权都增加k 4. 询问区间边权最大值 显然树剖 边权转点权然后就是树剖裸题了 怎样边权转点权 对于一个点u , 她的父亲是 v 将 u->v 的边权放到 u 上做点权 然后树剖最后的时候这样操作一波 1 if(a == b) 2 return; 3 if(dep[a] > dep[b]) 4 std::swap(a, b); 5 SgCover