【spoj375】Query on a tree【树链剖分】【或者动态树,那样常数就完了T_T】

hahahaha!
今天(3月12)我终于ac了……
orz Yan Big God!
他问我能不能 O(n) 建树……
并且提供了一个“反映射“的思想。
我想我们连反映射都可以不要……
鉴于ZKW的特殊性……
我们只要

    for(int i=1;i<n;++i){
        if(dep[d[i][0]]<dep[d[i][1]]) swap(d[i][0],d[i][1]);
        t[w[d[i][0]]+M]=d[i][2];
    }//w是树上节点到线段树的映射,M是ZKW线段树的偏移量
    for(int i=M-1;i;--i) t[i]=max(t[i<<1],t[i<<1|1]);

这样可以使 O(nlogn) 的建树复杂度降至 O(n) .
【这道题貌似用LCT也能A,不过splay常数大的要死(0.63,树剖0.23)- -我还以为我要T了呢- -】

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=30001;
typedef int arr[maxn<<1];
typedef int arr1[maxn];
int M,t[65536];
arr next,to;
arr1 list,fa,dep,size,son,top,w;
int rt,n,tot,ttot,z,d[maxn][3];
inline void add(int a,int b){
    ++tot;
    next[tot]=list[a];
    list[a]=tot;
    to[tot]=b;
    ++tot;
    next[tot]=list[b];
    list[b]=tot;
    to[tot]=a;

}
bool visit[20000];
void dfs(int v){
    size[v]=1;son[v]=0;
    for(int k=list[v];k;k=next[k])
        if(to[k]!=fa[v]){
            fa[to[k]]=v;
            dep[to[k]]=dep[v]+1;
            dfs(to[k]);
            size[v]+=size[to[k]];
            if(size[to[k]]>size[son[v]])
                son[v]=to[k];
        }
}
void buildtree(int v,int tp){
    w[v]=++z;top[v]=tp;
    if(son[v]) buildtree(son[v],top[v]);
    for(int k=list[v];k;k=next[k])
        if(to[k]!=fa[v]&&to[k]!=son[v])
            buildtree(to[k],to[k]);
}
inline void change(int p,int x){
    for(t[p+=M]=x,p>>=1;p;p>>=1) t[p]=max(t[p<<1],t[p<<1|1]);
}
int query(int L,int R){
    int ans=1<<31;
    for(L+=M-1,R+=M+1;L^R^1;L>>=1,R>>=1){
        if(~L&1) ans=max(ans,t[L^1]);
        if( R&1) ans=max(ans,t[R^1]);
    }
    return ans;
}
inline int find(int va,int vb){
    int f1=top[va],f2=top[vb],tmp=1<<31;
    while(f1!=f2){
        if(dep[f1]<dep[f2])
            swap(f1,f2),swap(va,vb);
        tmp=max(tmp,query(w[f1],w[va]));
        va=fa[f1];f1=top[va];
    }
    if(va==vb)return tmp;
    if(dep[va]>dep[vb]) swap(va,vb);

    return max(tmp,query(w[son[va]],w[vb]));
}
inline int read(){
    int x=0;
    char ch=getchar();
    while(!isdigit(ch)){ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x;
}
inline void init(){
    n=read();
    M=1;
    while(M<=n) M<<=1;
    memset(list,0,sizeof(int)*(n+1));
    ttot=rt=z=0;
    tot=0;
    for(int i=1;i<n;++i){
        d[i][0]=read(),d[i][1]=read(),d[i][2]=read();
        add(d[i][0],d[i][1]);
    }
    dfs(1);
    buildtree(1,1);
    for(int i=1;i<n;++i){
        if(dep[d[i][0]]<dep[d[i][1]]) swap(d[i][0],d[i][1]);
        t[w[d[i][0]]+M]=d[i][2];
    }
    for(int i=M-1;i;--i) t[i]=max(t[i<<1],t[i<<1|1]);
}
int a[10];
inline void print(int x){
    if(x) a[0]=0;
    else a[1]=0,a[0]=1;
    while(x) a[++a[0]]=x%10,x/=10;
    for(;a[0];--a[0])
        putchar(a[a[0]]+48);
    putchar('\n');
}
int main(){
    char ch;

    int x,y,t;
    for(t=read();t;--t){
        init();
        while(1){
            ch=getchar();
            while(ch!='D'&&ch!='Q'&&ch!='C') ch=getchar();
            if(ch=='D') break;
            if(ch=='Q')
                print(find(read(),read()));
            else{
                x=read(),y=read();
                change(w[d[x][0]],y);
            }
        }
        putchar('\n');
    }
    return 0;
}

这是LCT版的:(我旋转居然又写挂了- -)因为要把一条边也当做点来处理所以数组开大点- -

#include<cstdio>
#include<cstring>
#include<iostream>
#define STOP do{puts("there");while(1);}while(0)
using namespace std;
const int maxn=90001;
const int inf=1<<30;
struct node{
    node *f,*ch[2];
    int v,s,maxi;bool p,flip;
    inline bool isRoot();
    inline void rev(){flip^=1;}
    inline void upd(){
        s=ch[0]->s+ch[1]->s+1;
        maxi=max(v,max(ch[0]->maxi,ch[1]->maxi));
    }
}t[maxn],*stack[maxn],*cur=t;
int n;
inline bool node::isRoot(){return f==t||this!=f->ch[p];}
inline node *NewNode(node *f=t,int v=-inf){
    ++cur;
    cur->f=f;
    cur->ch[0]=cur->ch[1]=t;
    cur->s=1;
    cur->v=v;
    cur->flip=false;
    cur->maxi=v;
    return cur;
}
inline void sc(node *a,node *b,bool c){
    a->ch[c]=b;b->f=a;b->p=c;
}
inline void pushdown(node *x){
    if(x->flip){//其实if(x->ch[0]!=t)不必判断的
        if(x->ch[0]!=t) x->ch[0]->p^=1,x->ch[0]->flip^=1;
        if(x->ch[1]!=t) x->ch[1]->p^=1,x->ch[1]->flip^=1;
        swap(x->ch[0],x->ch[1]);
        x->flip=0;//!!!!!!!!!
    }
}
inline void rot(node *x){
    node *y=x->f;bool p=x->p;
    if(y->isRoot()) x->f=y->f;
    else sc(y->f,x,y->p);
    sc(y,x->ch[!p],p);
    sc(x,y,!p);
    y->upd();
}
inline void splay(node *x){
    int top;stack[top=1]=x;
    for(node *p=x;!p->isRoot();p=p->f) stack[++top]=p->f;
    while(top) pushdown(stack[top--]);
    while(!x->isRoot()){
        if(x->f->isRoot()) rot(x);
        else if(x->f->p==x->p) rot(x->f),rot(x);
        else rot(x),rot(x);
//      cout<<"锕";
    }//cout<<"铪\n";
    x->upd();
}
inline void splice(node *x){splay(x->f);sc(x->f,x,1);x->f->upd();splay(x);}
inline void expose(node *x){splay(x);while(x->f!=t) splice(x);}
inline void reroot(node *x){expose(x);x->ch[1]=t;x->upd();x->rev();}
inline void link(node *x,node *y){
    expose(x);
    x->ch[0]=y;x->upd();
}
inline int query(node *x,node *y){
    reroot(x);reroot(y);
    return y->maxi;
}
inline void change(node *x,int toWhat){
    splay(x);
    x->v=toWhat;
    x->upd();
}
inline int read(){
    int x=0;
    char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=x*10+ch-48,ch=getchar();
    return x;
}
node *idx[maxn<<1];
int tot,to[maxn<<1],next[maxn<<1],list[maxn],cost[maxn<<1];
inline void add(int a,int b,int c){
    next[++tot]=list[a];
    list[a]=tot;
    to[tot]=b;
    cost[tot]=c;
}
int q[maxn];
node *fa[maxn];
inline void bfs(){
    int head=0,tail=1,h;
    q[1]=1;
    fa[1]=t;
    while(head<tail){
        h=q[++head];
        idx[h]=NewNode(fa[h]?fa[h]:t);
        for(int k=list[h];k;k=next[k])
            if(!idx[to[k]]){
                idx[(k+1>>1)+n]=NewNode(idx[h],cost[k]);
                fa[to[k]]=idx[(k+1>>1)+n];
                q[++tail]=to[k];
            }

    }
}
inline void dfs(int x,node *f=t){
    idx[x]=NewNode(f);
}
#define CLR(x) memset(x,0,sizeof x)
inline void init(){
    memset(idx,0,sizeof(node*)*(cur-t+1));
    memset(list,0,sizeof(int)*(n+1));
    tot=0;
    cur=t;
    t[0].maxi=1<<31;
    t[0].f=t;
    t[0].ch[0]=t[0].ch[1]=t;
}
int main(){
    int T=read(),a,b,c;
    char cmd[10];
    while(T--){
        init();
        n=read();
        for(int i=1;i<n;++i){
            a=read(),b=read();c=read();
            add(a,b,c);add(b,a,c);
        }
        bfs();
        for(;;){
            scanf("%s",cmd);
            if(cmd[0]=='D') break;          
            else if(cmd[0]=='Q'){
                a=read();b=read();
                printf("%d\n",query(idx[a],idx[b]));
            }
            else{
                a=read();b=read();
                change(idx[a+n],b);
            }

        }
        putchar('\n');
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值