[POJ3237]树的维护

19 篇文章 0 订阅
13 篇文章 0 订阅

给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:
CHANGE i v:将第i条边的权值改成v。
NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。
QUERY a b:找出点a到点b路径上各边的最大权值。

冲着树链剖分来的,结果发现自己太弱了操作二的标记不会打,YY了2个多小时才写完QAQ

注意全部操作均为边权,于是要将边权下放到点上,具体看代码

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=210000+10;
struct seg{
    int l,r,delta;
    seg *lc,*rc;
    int mx,mi;
    seg():mx(0),mi(0),delta(0){}
};
seg *root=new seg;
int Belong[maxn],deep[maxn],size[maxn];
struct edge{
    int to,next,w,f;
}G[maxn*5];
int n,m,q,tot=0,h[maxn];
int fa[maxn][16],pos[maxn];
int ans,ind=0;
bool vis[maxn];
int X[maxn],Y[maxn],Z[maxn];
char ch;
int read(){
    int num=0; ch=getchar();
    while (ch<'!') ch=getchar();
    while (ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
    return num;
}

void add(int x,int y,int z){
    ++tot; G[tot].to=y; G[tot].w=z;
    G[tot].next=h[x]; h[x]=tot;
}

void DFS1(int x,int dep){
    deep[x]=dep; size[x]=1; vis[x]=1;
    for (int i=1;i<=15;++i){
        if (deep[x]<(1<<i)) break;
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    for (int i=h[x];i;i=G[i].next){
        int v=G[i].to;
        if (vis[v]) continue;
        fa[v][0]=x;
        DFS1(v,dep+1);
        size[x]+=size[v];
    }
}

void DFS2(int x,int L){
    int k=0; ++ind;
    pos[x]=ind;
    Belong[x]=L;
    for (int i=h[x];i;i=G[i].next)
       if (deep[x]<deep[G[i].to]&&size[G[i].to]>size[k])
          k=G[i].to;
    if (!k) return ;
    DFS2(k,L);
    for (int i=h[x];i;i=G[i].next)
       if (deep[x]<deep[G[i].to]&&k!=G[i].to)
          DFS2(G[i].to,G[i].to);
}

void build(seg *p,int l,int r){
    p->l=l; p->r=r;
    if (l+1==r) return;
    else if (l+1<r){
        int mid=(l+r)>>1;
        p->lc=new seg;
        p->rc=new seg;
        if (l<mid) build(p->lc,l,mid);
        if (mid<r) build(p->rc,mid,r);
    }
}

void updatemax(seg *p){//带懒标记的更新要谨慎……
    if (p->l+1==p->r) return;
    if (p->lc) p->mx=p->lc->mx;
    else{
        if (p->rc) p->mx=p->rc->mx;
        return;
    }
    if (p->rc)
        p->mx=max(p->mx,p->rc->mx);
}

void updatemin(seg *p){
    if (p->l+1==p->r) return;
    if (p->lc) p->mi=p->lc->mi;
    else{
        if (p->rc) p->mi=p->rc->mi;
        return;
    }
    if (p->rc)
        p->mi=min(p->mi,p->rc->mi);
}

void Swap(seg *p){
    int t=p->mx; p->mx=-p->mi; p->mi=-t;
}

void push_down(seg *p){//注意标记的写法,更新儿子的值
    if (!p->delta) return;
    else{
        p->delta=0;
        if (p->l+1==p->r) return;
        if (p->lc) p->lc->delta^=1;
        if (p->rc) p->rc->delta^=1;
        if (p->lc) Swap(p->lc);
        if (p->rc) Swap(p->rc);
    }
}

void update(seg *p,int pos,int val){
    if (p->l+1==p->r){p->mx=p->mi=val;return ;}
    else{
        int mid=(p->l+p->r)>>1;
        if (p->delta) push_down(p);
        if (pos<mid) update(p->lc,pos,val);
        if (mid<=pos) update(p->rc,pos,val);
        updatemax(p); updatemin(p);
    }
}

void Qmax(seg *p,int l,int r){//对于这道题要改就改到底,否则会影响程序正确性
    if (l<=p->l&&p->r<=r){
        push_down(p);
        if (p->l+1==p->r){
            ans=max(ans,p->mx);
            return;
        }
        if (p->lc) Qmax(p->lc,l,r);
        if (p->rc) Qmax(p->rc,l,r);
        updatemax(p); updatemin(p);
        ans=max(ans,p->mx);
    }else{
        push_down(p);
        if (p->l+1==p->r) return;
        int mid=(p->l+p->r)>>1;
        if (l<mid) Qmax(p->lc,l,r);
        if (mid<r) Qmax(p->rc,l,r);
        updatemax(p); updatemin(p);
    }
}

void change(seg *p,int l,int r){
    if (l<=p->l&&p->r<=r){
        p->delta^=1;
        if (p->l+1==p->r){Swap(p);}
        return;}
    else{
        if (p->delta) push_down(p);
        int mid=(p->l+p->r)>>1;
        if (l<mid) change(p->lc,l,r);
        if (mid<r) change(p->rc,l,r);
        updatemax(p); updatemin(p);
    }
}

int solve(int u,int v){
    int sum=-100000000;
    bool flag=0;
    if (u==9) flag=1;
    while (Belong[u]!=Belong[v]){
        ans=-100000000;
        Qmax(root,pos[Belong[u]],pos[u]+1);
        sum=max(sum,ans); u=fa[Belong[u]][0];
    }
    ans=-100000000; Qmax(root,pos[v]+1,pos[u]+1);//注意这里的pos[v]+1
    sum=max(sum,ans); return sum;
}

int LCA(int a,int b){
    if (deep[a]<deep[b]) swap(a,b);
    int t=deep[a]-deep[b];
    for (int i=0;i<=15;++i)
       if (t&(1<<i)) a=fa[a][i];
    for (int i=15;~i;i--)
       if (fa[a][i]!=fa[b][i]){
           a=fa[a][i];b=fa[b][i];}
    if (a==b) return a;
    else return fa[a][0];
}

void Fchange(int u,int v){
    while (Belong[u]!=Belong[v]){
        change(root,pos[Belong[u]],pos[u]+1);
        u=fa[Belong[u]][0];
        if (u==0) return;
    }
    change(root,pos[v]+1,pos[u]+1);
}

int main(){
    freopen("maintaintree.in","r",stdin);
    freopen("maintaintree.out","w",stdout);
    n=read();
    for (int i=1;i<n;++i){
        int x,y,z;
        x=read(); y=read(); z=read();
        add(x,y,z); add(y,x,z);
        X[i]=x; Y[i]=y; Z[i]=z;
    }
    DFS1(1,1);
    DFS2(1,1);
    build(root,1,ind+1);
    update(root,pos[1],-100000000);
    for (int i=1;i<n;++i){
        int u=X[i],v=Y[i],w=Z[i];
        if (deep[u]<deep[v]) swap(u,v);
        update(root,pos[u],w);
    }
    char ch[10]; int x,y;
    while (scanf("%s",ch)==1){
        if (ch[0]=='D') break;
        x=read(); y=read();
        if (ch[0]=='C'){//边权下放到深儿子上
            int a=X[x],b=Y[x],Aim;
            if(deep[a]>deep[b])Aim=a;else Aim=b;
            Z[Aim]=y; update(root,pos[Aim],y);
        }else if (ch[0]=='N'){
            int zx=LCA(x,y);
            Fchange(x,zx); Fchange(y,zx);
        }else{
            int zx=LCA(x,y);
            printf("%d\n",max(solve(x,zx),solve(y,zx)));
        }
    }
    //碉堡啦!
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值