[BZOJ2325][ZJOI2011][树链剖分][线段树]道馆之战

调了一个晚上
代码又臭又长

为什么zjoi2011的题目都是代码量那么大的题…

考虑在一条链上的情况,可以用线段树记录一个区间的八个值

  • 从左端点的A往右走的最大步数
  • 从左端点的B往右走的最大步数
  • 从右端点的A往左走的最大步数
  • 从右端点的B往左走的最大步数
  • 从右端点的A到左端点的A或从左端点的A到右端点的A的最大步数
  • 从右端点的A到左端点的B或从左端点的B到右端点的A的最大步数
  • 从右端点的B到左端点的A或从左端点的A到右端点的B的最大步数
  • 从右端点的B到左端点的B或从左端点的B到右端点的B的最大步数

然后维护瞎维护一下……
那么用树链剖分就可以把树上的情况转化成多个链的情况
树链剖分求一条(u,v)的路径的时候(u,lca)的路径要反转后再链上(v,lca)

这里和维护的部分坑了我一个晚上……

果然代码写的长就容易错……

#include 
#include 
#include 
#define N 30010

using namespace std;

int n,m,cnt,g,u,v;
int p[N],q[N],G[N],fa[N],top[N],son[N],siz[N],dpt[N];
char A[N],B[N];
char op;
struct edge{
    int t,nx;
}E[N<<1];
struct stp{
    int lara,larb,lbra,lbrb,Max,Empty,la,lb,ra,rb;
    stp(){lara=larb=lbra=lbrb=Max=Empty=la=lb=ra=rb=0;}
    friend stp operator +(stp a,stp b){
        stp r;
        if(a.lara&&b.lara) r.lara=a.lara+b.lara; if(a.larb&&b.lbra) r.lara=max(r.lara,a.larb+b.lbra);
        if(a.lara&&b.larb) r.larb=a.lara+b.larb; if(a.larb&&b.lbrb) r.larb=max(r.larb,a.larb+b.lbrb);
        if(a.lbra&&b.lara) r.lbra=a.lbra+b.lara; if(a.lbrb&&b.lbra) r.lbra=max(r.lbra,a.lbrb+b.lbra);
        if(a.lbra&&b.larb) r.lbrb=a.lbra+b.larb; if(a.lbrb&&b.lbrb) r.lbrb=max(r.lbrb,a.lbrb+b.lbrb);
        r.la=max(r.lara,r.larb); r.ra=max(r.lara,r.lbra); r.la=max(r.la,a.la); r.ra=max(r.ra,b.ra);
        r.lb=max(r.lbra,r.lbrb); r.rb=max(r.larb,r.lbrb); r.lb=max(r.lb,a.lb); r.rb=max(r.rb,b.rb);
        if(a.lara&&b.la) r.la=max(a.lara+b.la,r.la);
        if(a.larb&&b.lb) r.la=max(r.la,a.larb+b.lb);
        if(a.lbra&&b.la) r.lb=max(a.lbra+b.la,r.lb);
        if(a.lbrb&&b.lb) r.lb=max(r.lb,a.lbrb+b.lb);
        if(b.lara&&a.ra) r.ra=max(r.ra,b.lara+a.ra);
        if(b.lbra&&a.rb) r.ra=max(r.ra,b.lbra+a.rb);
        if(b.larb&&a.ra) r.rb=max(r.rb,b.larb+a.ra);
        if(b.lbrb&&a.rb) r.rb=max(r.rb,b.lbrb+a.rb);
        if(a.Empty||b.Empty) r.Empty=1;
        r.Max=max(r.la,r.lb);
        return r;
    }
    inline stp reverse(){
        stp r=*this;
        swap(r.larb,r.lbra);
        swap(r.la,r.ra);
        swap(r.lb,r.rb);
        return r;
    }
};
struct seg{
    int l,r;
    stp w;
}T[N<<2];

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    if(p1==p2){p2=(p1=buf)+fread(buf,1,100000,stdin);if(p1==p2) return EOF;}
    return *p1++;
}

inline void reaD(int &x){
    char c=nc(); x=0;
    for(;c>57||c<48;c=nc());for(;c>=48&&c<=57;x=x*10+c-48,c=nc());
}

inline void reaD(char &x){
    while((x=nc())!=46&&x!=35&&x!='Q'&&x!='C');
}

inline void Insert(int x,int y){
    E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
    E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}

void dfs0(int x,int f){
    fa[x]=f; dpt[x]=dpt[f]+1; siz[x]=1;
    for(int i=G[x];i;i=E[i].nx)
        if(E[i].t!=f){
            dfs0(E[i].t,x);
            if(siz[E[i].t]>siz[son[x]]) son[x]=E[i].t;
            siz[x]+=siz[E[i].t];
        }
}

void dfs1(int x,int tp){
    top[x]=tp; p[q[x]=++g]=x;
    if(son[x]) dfs1(son[x],tp);
    for(int i=G[x];i;i=E[i].nx)
        if(E[i].t!=fa[x]&&E[i].t!=son[x]) dfs1(E[i].t,E[i].t);
}

inline void set(int g,int x){
    T[g].w.lara=(A[p[x]]=='.');
    T[g].w.lbrb=(B[p[x]]=='.');
    if(A[p[x]]=='.'&&B[p[x]]=='.') T[g].w.larb=T[g].w.lbra=2;
    else T[g].w.larb=T[g].w.lbra=0;
    T[g].w.la=max(T[g].w.lara,T[g].w.larb); T[g].w.lb=max(T[g].w.lbra,T[g].w.lbrb);
    T[g].w.ra=max(T[g].w.lara,T[g].w.lbra); T[g].w.rb=max(T[g].w.larb,T[g].w.lbrb);
    if(A[p[x]]=='#'&&B[p[x]]=='#') T[g].w.Empty=1; else T[g].w.Empty=0;
    T[g].w.Max=max(T[g].w.la,T[g].w.ra);
}

void build(int g,int l,int r){
    T[g].l=l; T[g].r=r;
    if(l==r) return set(g,l);
    int mid=l+r>>1;
    build(g<<1,l,mid);
    build(g<<1|1,mid+1,r);
    T[g].w=T[g<<1].w+T[g<<1|1].w;
}

stp query(int g,int l,int r){
    if(T[g].l==l&&T[g].r==r) return T[g].w;
    int mid=T[g].l+T[g].r>>1;
    if(r<=mid) return query(g<<1,l,r);
    if(l>mid) return query(g<<1|1,l,r);
    return query(g<<1,l,mid)+query(g<<1|1,mid+1,r);
}

inline int query(int x,int y){
    int lara=0,larb=0,lbra=0,lbrb=0;
    int a=x,b=y,lca;
    while(top[a]!=top[b])
        if(dpt[top[a]]else a=fa[top[a]];
    lca=dpt[a]1; bool fir=1;
    for(;top[x]!=top[lca];x=fa[top[x]])
        if(fir)L=query(1,q[top[x]],q[x]).reverse(),fir=0;
        else L=L+query(1,q[top[x]],q[x]).reverse();
    if(fir)L=query(1,q[lca],q[x]).reverse();
    else L=L+query(1,q[lca],q[x]).reverse(); fir=1;
    for(;top[y]!=top[lca];y=fa[top[y]])
        if(fir) R=query(1,q[top[y]],q[y]),fir=0;
        else R=query(1,q[top[y]],q[y])+R;
    if(y!=lca) 
        if(fir) R=query(1,q[lca]+1,q[y]);
        else R=query(1,q[lca]+1,q[y])+R;
    return (L+R).Max;
}

void update(int g,int x){
    if(T[g].l==T[g].r) return set(g,x);
    int mid=T[g].l+T[g].r>>1;
    if(x<=mid) update(g<<1,x);
    else update(g<<1|1,x);
    T[g].w=T[g<<1].w+T[g<<1|1].w;
}

int main(){
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    reaD(n); reaD(m);
    for(int i=1;i0(1,0); dfs1(1,1);
    for(int i=1;i<=n;i++)
        reaD(A[i]),reaD(B[i]);
    build(1,1,g);
    for(int i=1;i<=m;i++){
        reaD(op);
        if(op=='Q'){
            reaD(u); reaD(v);
            printf("%d\n",query(u,v));
        }
        else{
            reaD(u); reaD(A[u]); reaD(B[u]);
            update(1,q[u]);
        }
    }
}

你可能感兴趣的:(树链剖分,线段树)