LOJ10056

LOJ10056

实际上,这题只要任选一个根,将无根树转为有根树,构造val[x]表示从根到x节点的异或和,就变成模板LOJ10050了
为什么这样是对的?

  • 异或同一个数偶数次等于啥也没干
  • 异或满足交换律( x xor y=y xor x x   x o r   y = y   x o r   x

    所以可以构造“前缀异或”

  • 若(x,y)不在同一条到根的树链上,显然val[x] xor val[y]没问题
    LOJ10056_第1张图片

  • 若(x,y)各自到根的树链有并链,则
    (val[x] xor val[z])xor(val[y] xor val[z])
    =val[x] xor val[y] xor val[z] xor val[z]
    =val[x] xor val[y]
    LOJ10056_第2张图片
  • 若(x,y)在同一条到根的树链上,val[x] xor val[y]=val[y] xor val[x]
    LOJ10056_第3张图片
    然后就好了,复杂度 O(N302) O ( N ∗ 30 ∗ 2 )
#include
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define __R register
using namespace std;
static char buf[1000000],*p1=buf,*p2=buf;
const int maxn=(1e5)+5,L=31;
int n,Ans,val[maxn],Pow[L+5];
int tot,son[maxn<<1],nxt[maxn<<1],lnk[maxn],w[maxn<<1];
void add_e(int x,int y,int z){son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;}
int read(){
    int ret=0;char ch=gt();
    while(ch<'0'||ch>'9') ch=gt();
    while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
    return ret;
}
struct Trie{
    int tot,s[maxn*L][3],cnt[maxn*L];
    inline void insert(int x){
        __R int rot=0;__R bool p;
        for(__R int i=L-1;i>=0;i--) rot=s[rot][p=(x>>i)&1]=s[rot][p]?s[rot][p]:++tot;
    }
    inline void check(int x){
        __R int rot1=0,rot2=0,now=0;__R bool p;
        for(__R int i=L-1;i>=0;i--){
            rot1=s[rot1][p=(x>>i)&1];
            if(s[rot2][!p]) now|=Pow[i],rot2=s[rot2][!p];else rot2=s[rot2][p];
            if(now+Pow[i]-1<=Ans) return;
        }
        Ans=now;
    }
}T;
void DFS(int x,int fa){for(__R int j=lnk[x];j;j=nxt[j])if(son[j]!=fa) T.insert(val[son[j]]=val[x]^w[j]),DFS(son[j],x);}
int main(){
    n=read();
    for(__R int i=0;i1<for(__R int i=1;iint x=read(),y=read(),z=read();
        add_e(x,y,z),add_e(y,x,z);
    }
    DFS(1,-1);
    for(__R int i=1;i<=n;i++) T.check(val[i]);
    printf("%d\n",Ans);
    return 0;
}

你可能感兴趣的:(贪心,LOJ,Trie)