1. 程式人生 > >BZOJ_5338_ [TJOI2018]xor_可持久化trie

BZOJ_5338_ [TJOI2018]xor_可持久化trie

ont oot 用兩個 \n dfs namespace space dep pre

BZOJ_5338_ [TJOI2018]xor_可持久化trie

Description

有一棵點數為N的樹,樹邊有邊權。給你一個在0~N之內的正整數K,你要在這棵樹中選擇K個點,將其染成黑色,並 將其他的N-K個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。 問收益最大值是多少。

Input

第一行兩個整數N,K。 接下來N-1行每行三個正整數fr,to,dis,表示該樹中存在一條長度為dis的邊(fr,to)。 輸入保證所有點之間是聯通的。 N<=2000,0<=K<=N

Output

輸出一個正整數,表示收益的最大值。

Sample Input

5 2
1 2 3
1 5 1
2 3 1
2 4 2

Sample Output

17
【樣例解釋】
將點1,2染黑就能獲得最大收益。

HINT

2017.9.12新加數據一組 By GXZlegend


博客裏沒有幾道可持久化trie的題,還是更一篇吧。

同時要求子樹和兩點路徑上的信息,

只能用兩個序維護一下,然後可持久化一下隨便搞搞。

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define N 200050
int head[N],to[N],nxt[N],val[N],cnt,n,m,be[N],ed[N],tot,root[N],t[N*33],sanae,ch[N*33][2],son[N],siz[N],fa[N],dep[N],top[N];
int t2[N*33],ch2[N*33][2],dfn[N],marisa,reimu,root2[N];
inline void add(int u,int v) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void update(int x,int c,int &y,int q) {
    y=++sanae; int p=y; t[p]=t[q]+c;
    int i;
    for(i=30;i>=0;i--) {
        int k=(x>>i)&1;
        ch[p][k]=++sanae; ch[p][!k]=ch[q][!k];
        p=ch[p][k]; q=ch[q][k]; t[p]=t[q]+c;
    }
}
void upd(int x,int c,int &y,int q) {
    y=++reimu; int p=y; t2[p]=t2[q]+c;
    // printf("upd---%d %d %d %d\n",p,q,t2[p],t2[q]);
    int i;
    for(i=30;i>=0;i--) {
        int k=(x>>i)&1;
        ch2[p][k]=++reimu; ch2[p][!k]=ch2[q][!k];
        p=ch2[p][k]; q=ch2[q][k]; t2[p]=t2[q]+c;
    }
}
void dfs(int x,int y) {
    dfn[x]=++marisa; upd(val[x],1,root2[marisa],root2[marisa-1]);
    // printf("dfs---%d %d %d %d\n",root2[marisa],root2[marisa-1],t2[root2[marisa]],t2[root2[marisa-1]]);
    // printf("%d %d %d %d\n",t2[root2[1]],t2[root2[2]],t2[root2[3]],t2[root2[4]]);
    int i; be[x]=++tot; update(val[x],1,root[tot],root[tot-1]); siz[x]=1; fa[x]=y; dep[x]=dep[y]+1;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            dfs(to[i],x); siz[x]+=siz[to[i]]; if(siz[son[x]]<siz[to[i]]) son[x]=to[i];
        }
    }
    ed[x]=++tot; update(val[x],-1,root[tot],root[tot-1]);
}
void dfs2(int x,int t) {
    top[x]=t;
    if(son[x]) dfs2(son[x],t);
    int i;
    for(i=head[x];i;i=nxt[i])if(to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]);
}
int lca(int x,int y) {
    while(top[x]!=top[y]) {
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        y=fa[top[y]];
    }
    return dep[x]<dep[y]?x:y;
}
int solve1(int x,int y,int v) {
    // printf("%d %d %d %d\n",x,y,t2[x],t2[y]);
    int i,re=0;
    for(i=30;i>=0;i--) {
        int k=!((v>>i)&1);
        if(t2[ch2[y][k]]-t2[ch2[x][k]]) {
            re+=(1<<i); x=ch2[x][k]; y=ch2[y][k];
        }else x=ch2[x][!k],y=ch2[y][!k];
    }
    return re;
}
int solve2(int x,int y,int z,int w,int v) {
    int i,re=0;
    for(i=30;i>=0;i--) {
        int k=!((v>>i)&1);
        if(t[ch[x][k]]+t[ch[y][k]]-t[ch[z][k]]-t[ch[w][k]]>0) re+=(1<<i),x=ch[x][k],y=ch[y][k],z=ch[z][k],w=ch[w][k];
        else x=ch[x][!k],y=ch[y][!k],z=ch[z][!k],w=ch[w][!k];
    }
    return re;
}
int main() {
    scanf("%d%d",&n,&m);
    int i,x,y,opt,z;
    for(i=1;i<=n;i++) scanf("%d",&val[i]);
    for(i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs(1,0); dfs2(1,1);    
    // printf("%d %d %d %d\n",t2[root2[1]],t2[root2[2]],t2[root2[3]],t2[root2[4]]);
    for(i=1;i<=m;i++) {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==1) {
            // printf("%d\n",root2[dfn[x]-1]);
            printf("%d\n",solve1(root2[dfn[x]-1],root2[dfn[x]+siz[x]-1],y));
        }else {
            scanf("%d",&z);
            int l=lca(x,y);
            printf("%d\n",solve2(root[be[x]],root[be[y]],root[be[l]],root[be[fa[l]]],z));
        }
    }
}

BZOJ_5338_ [TJOI2018]xor_可持久化trie