[POJ3237]树的维护

来源:互联网 发布:360解压缩软件 编辑:程序博客网 时间:2024/05/07 17:32

给你由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)));        }    }    //碉堡啦!}
1 0
原创粉丝点击