zoukankan      html  css  js  c++  java
  • 【SPOJ】—Qtree系列题解

    Query on a tree

    SPOJ
    洛咕

    把边权丢给儿子就可以了
    注意一下细节,其他的没什么
    还有洛咕和SPOJSPOJ要求不一样
    这是洛咕的

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=100005;
    int adj[N],nxt[N<<1],to[N<<1],a[N],val[N<<1];
    int n,cnt,tot;
    char op[10];
    inline void addedge(int u,int v,int w){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
    }
    int idx[N],top[N],dep[N],fa[N],pos[N],siz[N],son[N];
    void dfs1(int u){
        siz[u]=1;
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u])continue;
            a[v]=val[e],fa[v]=u,dep[v]=dep[u]+1;
            dfs1(v),siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])son[u]=v;
        }
    }
    void dfs2(int u,int tp){
        top[u]=tp,pos[u]=++tot,idx[tot]=u;
        if(son[u])dfs2(son[u],tp);
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u]||v==son[u])continue;
            dfs2(v,v);
        }
    }
    int tr[N<<2];
    #define lc (u<<1)
    #define rc ((u<<1)|1)
    #define mid ((l+r)>>1)
    inline void pushup(int u){
        tr[u]=max(tr[lc],tr[rc]);
    }
    void build(int u,int l,int r){
        if(l==r){tr[u]=a[idx[l]];return;}
        build(lc,l,mid),build(rc,mid+1,r);
        pushup(u);
    }
    void update(int u,int l,int r,int p,int k){
        if(l==r){tr[u]=k;return;}
        if(p<=mid)update(lc,l,mid,p,k);
        else update(rc,mid+1,r,p,k);
        pushup(u);
    }
    int query(int u,int l,int r,int st,int des){
        if(st>des)return 0;
        if(st<=l&&r<=des)return tr[u];
        int res=0;
        if(st<=mid)res=max(res,query(lc,l,mid,st,des));
        if(mid<des)res=max(res,query(rc,mid+1,r,st,des));
        return res;
    }
    inline int pathquery(int u,int v){
        int res=0;
        while(top[u]!=top[v]){
            if(dep[top[u]]<dep[top[v]])swap(u,v);
            res=max(res,query(1,1,n,pos[top[u]],pos[u]));
            u=fa[top[u]];
        }
        if(dep[u]>dep[v])swap(u,v);
        res=max(res,query(1,1,n,pos[u]+1,pos[v]));
        return res;
    }
    int U[N],V[N];
    int main(){
        n=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read(),w=read();
            addedge(u,v,w),addedge(v,u,w);
            U[i]=u,V[i]=v;
        }
        dfs1(1);
        dfs2(1,1);
        build(1,1,n);
        while(1){
            scanf("%s",op);
            if(op[0]=='Q'){
                int u=read(),v=read();
                cout<<pathquery(u,v)<<'
    ';
            }
            if(op[0]=='C'){
                int i=read(),k=read();
                if(fa[U[i]]==V[i])update(1,1,n,pos[U[i]],k);
                else update(1,1,n,pos[V[i]],k);
            }
            else if(op[0]=='D')break;
        }
    }
    

    Query on a tree II

    SPOJ
    洛咕
    也很简单
    边权记一下前缀和在lcalca差分一下
    kk个倍增就可以了,处理一下在lcalca的哪边

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=100005;
    int adj[N],nxt[N<<1],to[N<<1],a[N],val[N<<1],dep[N],dis[N];
    int n,cnt,tot;
    int f[N][22];
    char op[10];
    inline void addedge(int u,int v,int w){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
    }
    void dfs(int u){
        for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==f[u][0])continue;
            dis[v]=dis[u]+val[e],f[v][0]=u,dep[v]=dep[u]+1;dfs(v);
        }
    }
    inline int Lca(int u,int v){
        if(dep[u]<dep[v])swap(u,v);
        if(u==v)return u;
        for(int i=20;~i;i--){
            if(dep[f[u][i]]>=dep[v])u=f[u][i];
        }
        if(u==v)return u;
        for(int i=20;~i;i--){
            if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
        }
        return f[u][0];
    }
    inline int Kth(int u,int k){
        for(int i=20;~i;i--){
            if((1<<i)<=k){
                k-=(1<<i),u=f[u][i];
            }
        }
        return u;
    }
    int main(){
        int T=read();
        while(T--){
            memset(adj,0,sizeof(adj)),cnt=0;
            memset(f,0,sizeof(f));
            dis[1]=0;
            n=read();
            for(int i=1;i<n;i++){
                int u=read(),v=read(),w=read();
                addedge(u,v,w),addedge(v,u,w);
            }
            dfs(1);
            while(1){
                scanf("%s",op);
                if(op[0]=='D'&&op[1]=='I'){
                    int u=read(),v=read();
                    int lca=Lca(u,v);
                    cout<<dis[u]+dis[v]-2*dis[lca]<<'
    ';
                }
                else if(op[0]=='K'){
                    int u=read(),v=read();
                    int k=read();
                    int lca=Lca(u,v);
                    if(dep[u]-dep[lca]+1>=k)cout<<Kth(u,k-1)<<'
    ';
                    else cout<<Kth(v,dep[v]-dep[lca]-k+dep[u]-dep[lca]+1)<<'
    ';
                }
                else if(op[0]=='D'&&op[1]=='O')break;
            }
        }
    }
    

    Query on a tree again!

    SPOJ
    洛咕

    树剖维护一下,把黑点权值当做1,线段树上二分查找一下最左边的就可以了

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=100005;
    int adj[N],nxt[N<<1],to[N<<1],a[N],val[N<<1],dep[N],dis[N];
    int tr[N<<2],plc[N<<2],cnt,tot,n,q;
    #define lc (u<<1)
    #define rc ((u<<1)|1)
    #define mid ((l+r)>>1)
    int idx[N],top[N],fa[N],pos[N],siz[N],son[N];
    inline void addedge(int u,int v){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    }
    inline void pushup(int u){
        tr[u]=tr[lc]+tr[rc];
        plc[u]=tr[lc]?plc[lc]:(tr[rc]?plc[rc]:-1);
    }
    void update(int u,int l,int r,int p){
        if(l==r){tr[u]^=1,plc[u]=tr[u]?idx[l]:-1;return;}
        if(p<=mid)update(lc,l,mid,p);
        else update(rc,mid+1,r,p);
        pushup(u);
    }
    int query(int u,int l,int r,int st,int des){
        if(st>r||des<l)return -1;
        if(st<=l&&r<=des)return plc[u];
        int k=query(lc,l,mid,st,des);
        if(k==-1)return query(rc,mid+1,r,st,des);
        else return k;
    }
    void dfs1(int u){
        siz[u]=1;
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u])continue;
            dep[v]=dep[u]+1,fa[v]=u;
            dfs1(v),siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])son[u]=v;
        }
    }
    void dfs2(int u,int tp){
        top[u]=tp,pos[u]=++tot,idx[tot]=u;
        if(son[u])dfs2(son[u],tp);
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u]||v==son[u])continue;
            dfs2(v,v);
        }
    }
    inline int pathquery(int u){
        int res=-1;
        while(top[u]!=1){
            int now=query(1,1,n,pos[top[u]],pos[u]);
            if(now!=-1)res=now;
            u=fa[top[u]];
        }
        int now=query(1,1,n,1,pos[u]);
        if(now!=-1)res=now;
        return res;
    }
    int main(){
        n=read(),q=read();
        memset(plc,-1,sizeof(plc));
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            addedge(u,v),addedge(v,u);
        }
        dfs1(1),dfs2(1,1);
        while(q--){
            int op=read(),u=read();
            if(op==0){
                update(1,1,n,pos[u]);
            }
            else{
                cout<<pathquery(u)<<'
    ';
            }
        }
    }
    

    Query on a tree IV

    SPOJ
    洛咕

    学习一下如何用LctLct维护子树信息

    具体的是对于实儿子直接统计
    对于虚儿子我们开一个setset来维护
    发现影响虚实关系的只有accessaccess
    就在accessaccess的时候加入原来的实儿子,删去现在的虚儿子的值

    考虑处理三个数组lmx,rmx,mxlmx,rmx,mx
    lmxlmx表示当前实链的顶部的点的最远的一个距离
    rmxrmx表示当前实链的底端的最远的一个距离
    注意这2个玩意其实对于当前点的答案没用,只是为了给下一个父亲统计的
    因为一颗辅助树其实维护就是一条深度递增的链
    子树就是一段子链
    mxmx则是经过当前点的最大答案

    并维护22set:pathchainset:path、chain分别表示子树的最大答案和子树最长的距离

    考虑现在在辅助树中pushuppushup其实是把两条链的答案拼起来
    顺带把虚子树也考虑进去
    至于转移细节可以自己看
    主要是讲一下个人的理解

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=200005;
    const int inf=1e9;
    int n,cnt,adj[N],nxt[N<<1],to[N<<1],val[N<<1],a[N],col[N],ans;
    multiset<int> chain[N],path[N];
    inline int fir(const multiset<int> &s){
        return s.empty()?-inf:*s.rbegin();
    }
    inline int sec(const multiset<int> &s){
        return s.size()<=1?-inf:*(++s.rbegin());
    }
    inline void addedge(int u,int v,int w){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
    }
    int lmx[N],rmx[N],mx[N],sum[N],w[N];
    inline void chemx(int &a,int b){
        a=a>b?a:b;
    }
    namespace Lct{
        int q[N],son[N][2],fa[N];
        #define lc(u) son[u][0]
        #define rc(u) son[u][1]
        inline bool isrt(int u){
            if(!fa[u])return 1;
            return lc(fa[u])!=u&&rc(fa[u])!=u;
        }
        inline bool isrc(int u){
            return rc(fa[u])==u;
        }
        void pushup(int u){
            sum[u]=sum[lc(u)]+sum[rc(u)]+a[u];
            int cha=max(w[u],fir(chain[u]));
            int L=max(cha,rmx[lc(u)]+a[u]);
            int R=max(cha,lmx[rc(u)]);
            lmx[u]=max(lmx[lc(u)],sum[lc(u)]+a[u]+R);
            rmx[u]=max(rmx[rc(u)],sum[rc(u)]+L);
            mx[u]=max(rmx[lc(u)]+a[u]+R,lmx[rc(u)]+L);
            chemx(mx[u],max(mx[lc(u)],mx[rc(u)]));
            chemx(mx[u],fir(path[u]));
            chemx(mx[u],fir(chain[u])+sec(chain[u]));
            if(w[u]==0) chemx(mx[u],max(fir(chain[u]),0));
        }
        inline void rotate(int v){
            int u=fa[v],z=fa[u];
            int t=rc(u)==v;
            if(!isrt(u))son[z][rc(z)==u]=v;
            fa[v]=z;
            fa[son[v][t^1]]=u,son[u][t]=son[v][t^1];
            son[v][t^1]=u,fa[u]=v;
            pushup(u),pushup(v);
        }
        inline void splay(int u){
            while(!isrt(u)){
                if(!isrt(fa[u])){
                    if(isrc(u)==isrc(fa[u]))rotate(fa[u]);
                    else rotate(u);
                }
                rotate(u);
            }
            pushup(u);
        }
        inline void access(int u){
            for(int v=0;u;v=u,u=fa[u]){
                splay(u);
                if(rc(u))path[u].insert(mx[rc(u)]),chain[u].insert(lmx[rc(u)]);
                if(v)path[u].erase(path[u].find(mx[v])),chain[u].erase(chain[u].find(lmx[v]));
                rc(u)=v,fa[v]=u,pushup(u);
            }
        }
    	void update(int u){
    	    access(u),splay(u);
    	    col[u]^=1,w[u]=col[u]?(-inf):0;
    	    pushup(u),ans=mx[u];
    	}
    }
    using namespace Lct;
    void dfs(int u){
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u])continue;
            a[v]=val[e],fa[v]=u;
            dfs(v);
            chain[u].insert(lmx[v]),path[u].insert(mx[v]);
        }
        pushup(u);
    }
    char op[4];
    int main(){
        n=read();
        for(int i=0;i<=n;i++)lmx[i]=rmx[i]=mx[i]=-inf;
        for(int i=1;i<n;i++){
            int u=read(),v=read(),w=read();
            addedge(u,v,w),addedge(v,u,w);
        }
        dfs(1);
        ans=mx[1];int q=read();
        while(q--){
            scanf("%s",op);
            if(op[0]=='A'){
                if(ans<0)puts("They have disappeared.");
                else cout<<ans<<'
    ';
            }
            else {int u=read();update(u);}
        }
    }
    

    Query on a tree V

    SPOJ
    洛咕

    如果理解了44的话其实5还要简单一些
    还不是任意路径
    还是lmnlmn表示实链顶端的点的最小答案
    rmnrmn表示实链底端的点最小答案
    最后当前询问点已经到根了而且是链的最深点就可以直接输出rmxrmx就是了
    (没明白的自己思考)

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=200005;
    const int inf=1e9;
    int n,cnt,adj[N],nxt[N<<1],to[N<<1],col[N],ans;
    multiset<int> chain[N];
    inline int fir(int u){
        return chain[u].size()?*chain[u].begin():inf;
    }
    inline void addedge(int u,int v){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    }
    namespace Lct{
        int son[N][2],fa[N],lmn[N],rmn[N],siz[N];
        #define lc(u) son[u][0]
        #define rc(u) son[u][1]
        inline bool isrc(int u){
            return rc(fa[u])==u;
        }
        inline bool isrt(int u){
            return fa[u]?(lc(fa[u])!=u&&rc(fa[u])!=u):1;
        }
        inline void pushup(int u){
            siz[u]=siz[lc(u)]+siz[rc(u)]+1;
            lmn[u]=min(lmn[lc(u)],siz[lc(u)]+min((col[u]?0:inf),min(fir(u)+1,lmn[rc(u)]+1)));
            rmn[u]=min(rmn[rc(u)],siz[rc(u)]+min((col[u]?0:inf),min(fir(u)+1,rmn[lc(u)]+1)));
        }
        inline void rotate(int v){
            int u=fa[v],z=fa[u];
            int t=rc(u)==v;
            if(!isrt(u))son[z][rc(z)==u]=v;
            fa[v]=z;
            fa[son[v][t^1]]=u,son[u][t]=son[v][t^1];
            son[v][t^1]=u,fa[u]=v;
            pushup(u),pushup(v);
        }
        inline void splay(int u){
            while(!isrt(u)){
                if(!isrt(fa[u])){
                    if(isrc(fa[u])==isrc(u))rotate(fa[u]);
                    else rotate(u);
                }
                rotate(u);
            }
        }
        inline void access(int u){
            for(int v=0;u;v=u,u=fa[u]){
                splay(u);
                if(rc(u))chain[u].insert(lmn[rc(u)]);
                if(v)chain[u].erase(chain[u].find(lmn[v]));
                rc(u)=v;
                pushup(u);
            }
        } 
    }
    using namespace Lct;
    void dfs(int u){
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u])continue;
            fa[v]=u,chain[u].insert(inf);
            dfs(v);
        }pushup(u);
    }
    int main(){
        n=read();lmn[0]=rmn[0]=inf;
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            addedge(u,v),addedge(v,u);
        }
        dfs(1);
        int q=read();
        while(q--){
            int op=read(),u=read();
            if(op==1){
                access(u),splay(u);
                cout<<((rmn[u]>n)?-1:rmn[u])<<'
    ';
            }
            else{
                access(u),splay(u);
                col[u]^=1;pushup(u);
            }
        }
        return 0;
    }
    

    Query on a tree VI

    SPOJ
    洛咕

    相当于维护树上联通块
    一个直观的做法是维护2颗LctLct
    每次枚举所有相邻点并连边
    但显然复杂度不对

    考虑类似将边权转点权的方式
    把点的颜色转到边上
    直接向父亲连边维护sizsiz就可以了

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=100005;
    const int inf=1e9;
    #define lc(u) son[u][0]
    #define rc(u) son[u][1]
    struct Lct{
        int q[N],son[N][2],siz[N],val[N],fa[N];
        inline bool isrc(int u){
            return rc(fa[u])==u;
        }
        inline bool isrt(int u){
            return fa[u]?(lc(fa[u])!=u&&rc(fa[u])!=u):1;
        }
        inline void pushup(int u){
            siz[u]=siz[lc(u)]+siz[rc(u)]+val[u]+1;
        }
        inline void rotate(int v){
            int u=fa[v],z=fa[u];
            int t=rc(u)==v;
            if(!isrt(u))son[z][rc(z)==u]=v;
            fa[v]=z;
            fa[son[v][t^1]]=u,son[u][t]=son[v][t^1];
            son[v][t^1]=u,fa[u]=v;
            pushup(u),pushup(v);
        }
        inline void splay(int u){
            while(!isrt(u)){
                if(!isrt(fa[u])){
                    if(isrc(u)==isrc(fa[u]))rotate(fa[u]);
                    else rotate(u);
                }
                rotate(u);
            }
            pushup(u);
        }
        inline void access(int u){
             for(int v=0;u;v=u,u=fa[u]){
             	splay(u);
             	if(rc(u))val[u]+=siz[rc(u)];
             	if(v)val[u]-=siz[v];
             	rc(u)=v,pushup(u);
             }
        }
        inline void link(int u,int v){
            splay(u),fa[u]=v;
            access(v),splay(v),siz[v]+=siz[u],val[v]+=siz[u];
        }
        inline void cut(int u,int v){
            access(u),splay(u);
            lc(u)=fa[lc(u)]=0;
            pushup(u);
        }
        inline int findrt(int u){
            access(u),splay(u);
            while(lc(u))u=lc(u);
            splay(u);return u;
        }
    }T[2];
    int n,cnt,adj[N],nxt[N<<1],to[N<<1],col[N],fa[N];
    inline void addedge(int u,int v){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    }
    void dfs(int u){
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u])continue;
            fa[v]=u,dfs(v),T[0].link(v,u);
        }
    }
    int main(){
        n=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            addedge(u,v),addedge(v,u);
        }
        dfs(1),fa[1]=n+1,T[0].link(1,fa[1]);
        int m=read();
        while(m--){
            int op=read(),u=read();
            if(op==0){
                int v=T[col[u]].findrt(u);
                cout<<T[col[u]].siz[T[col[u]].rc(v)]<<'
    ';
            }
            else{
                T[col[u]].cut(u,fa[u]);
                T[col[u]^1].link(u,fa[u]);
                col[u]^=1;
            }
        }
    }
    

    Query on a tree

    SPOJ
    洛咕

    求联通块最大值带修改
    和上一道一样的套路
    再像之前454、5一样维护一个子树最大值就可以了

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=100005;
    const int inf=2147483647;
    #define lc(u) son[u][0]
    #define rc(u) son[u][1]
    int n,val[N],adj[N<<1],nxt[N<<1],to[N<<1];
    inline void chemx(int &a,int b){
        a=a>b?a:b;
    }
    struct Lct{
        multiset<int> chain[N];
        inline int fir(int u){
            return chain[u].size()?*chain[u].rbegin():-inf;
        } 
        int mx[N],fa[N],son[N][2];
        Lct(){mx[0]=-inf;}
        inline bool isrc(int u){
            return rc(fa[u])==u;
        }
        inline bool isrt(int u){
            return fa[u]?(rc(fa[u])!=u&&lc(fa[u])!=u):1;
        }
        inline void pushup(int u){
            mx[u]=val[u];
            chemx(mx[u],max(mx[lc(u)],mx[rc(u)]));
            chemx(mx[u],fir(u));
        }
        inline void rotate(int v){
            int u=fa[v],z=fa[u];
            int t=rc(u)==v;
            if(!isrt(u))son[z][rc(z)==u]=v;
            fa[v]=z;
            fa[son[v][t^1]]=u,son[u][t]=son[v][t^1];
            son[v][t^1]=u,fa[u]=v;
            pushup(u),pushup(v);
        }
        inline void splay(int u){
            while(!isrt(u)){
                if(!isrt(fa[u])){
                    if(isrc(fa[u]==isrc(u)))rotate(fa[u]);
                    else rotate(u);
                }
                rotate(u);
            }
            pushup(u);
        }
        inline void access(int u){
            for(int v=0;u;v=u,u=fa[u]){
                splay(u);
                if(rc(u))chain[u].insert(mx[rc(u)]);
                if(v)chain[u].erase(chain[u].find(mx[v]));
                rc(u)=v,pushup(u);
            }
        }
        inline int findrt(int u){
            access(u),splay(u);
            while(lc(u))u=lc(u);
            splay(u);return u;
        }
        inline void link(int u,int v){
            splay(u);
            access(v),splay(v);
            fa[u]=v;
            rc(v)=u,pushup(v);
        }
        inline void cut(int u,int v){
            access(u),splay(u);
            fa[lc(u)]=0,lc(u)=0;
            pushup(u);
        }
        inline void update(int u,int k){
            access(u),splay(u);
            val[u]=k,pushup(u);
        }
        inline int query(int u){
            u=findrt(u);return mx[rc(u)];
        }
    }T[2];
    int fa[N],col[N],cnt;
    inline void  addedge(int u,int v){
        nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    }
    void dfs(int u){
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(v==fa[u])continue;
            fa[v]=u,T[col[v]].link(v,u);
            dfs(v);
        }
    }
    int main(){
        n=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            addedge(u,v),addedge(v,u);
        }
        for(int i=1;i<=n;i++)col[i]=read();
        for(int i=1;i<=n;i++)val[i]=read();
        dfs(1),fa[1]=n+1;
        T[col[1]].link(1,fa[1]);
        int m=read();
        while(m--){
            int op=read(),u=read();
            if(op==0){
                cout<<T[col[u]].query(u)<<'
    ';
            }
            else if(op==1){
                T[col[u]].cut(u,fa[u]);
                col[u]^=1,T[col[u]].link(u,fa[u]);
            }
            else{
                int k=read();
                T[col[u]].update(u,k);
            }
        }
    }
    

    完结撒花~!

  • 相关阅读:
    Linux中grep命令的12个实践例子
    进程调度函数schedule()分析
    spin_lock、spin_lock_irq、spin_lock_irqsave区别
    耳机接电话挂断功能
    英文月份
    Linux 学习之路:认识shell和bash
    Solution:Cannot pull with rebase: You have unstaged changes in Github
    Selenium Webdriver——操作隐藏的元素(四)
    Selenium Webdriver——操作隐藏的元素(三)switchTo().frame()
    selenium webdriver处理HTML5 的视频播放
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145602.html
Copyright © 2011-2022 走看看