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

来源:互联网 发布:淘宝偷图技巧 编辑:程序博客网 时间:2024/05/23 10:22

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