P3292 [SCOI2016]幸运数字 线性基

正解:线性基+倍增

解题报告:

先放下传送门QAQ

然后这题,其实没什么太大的技术含量,,,?就几个知识点套在一起,除了代码长以外没任何意义,主要因为想复习下线性基的题目所以还是写下,,,

随便写下思路趴,首先多个数异或显然线性基,然后因为是在树上所以可以考虑倍增预处理线性基,插入合并查询都基操我不说了QAQ

然后因为我树剖不熟练所以我用的树剖,,,当然倍增一样的反正都差不多?反正就xxj[i][j]:第i个点向上跳j步的线性基,和普通树上跳lca什么都一样的做法,over

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#define int long long
#define gc getchar()
#define mp make_pair
#define t(i) edge[i].to
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ll i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];i;i=edge[i].nxt)

const int N=23000;
int n,q,poww[65]={1},val[N],ed_cnt,head[N],hs[N],sz[N],dfn[N],dfn_cnt,top[N],lg[N],fa[N],dep[N];
struct ed{int to,nxt;}edge[N<<1];
struct xxj
{
    ll a[65];int num_cnt;
    il void clr(){memset(a,0,sizeof(a));num_cnt=0;}
    il void insert(ll x){if(num_cnt==61)return;my(i,60,0)if(x&poww[i]){x^=a[i];if(!a[i]){a[i]=x,++num_cnt;return;}}}
    il ll mx(){ll ret=0;my(i,60,0)ret=max(ret,ret^a[i]);return ret;}
}gdgs[18][N],as;

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch<'0' || ch>'9'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void ad(ri x,ri y){edge[++ed_cnt]=(ed){x,head[y]};head[y]=ed_cnt;edge[++ed_cnt]=(ed){y,head[x]};head[x]=ed_cnt;}
void dfs1(ri x,ri fat)
{
    sz[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;
    e(i,x)if(fat^t(i)){dfs1(t(i),x);sz[x]+=sz[t(i)];if(sz[t(i)]>sz[hs[x]])hs[x]=t(i);}
}
void dfs2(ri x,ri tp)
{
    top[x]=tp;dfn[x]=++dfn_cnt;gdgs[0][dfn_cnt].insert(val[x]);
    if(hs[x])dfs2(hs[x],tp);e(i,x)if(!dfn[t(i)])dfs2(t(i),t(i));
}
il xxj merg(xxj gd,xxj gs){rp(i,0,60){if(gd.num_cnt==61)return gd;if(gs.a[i])gd.insert(gs.a[i]);}return gd;}
il xxj gt(ri l,ri r){ri ln=lg[r-l+1];return merg(gdgs[ln][l],gdgs[ln][r-poww[ln]+1]);}

main()
{
//    freopen("3292.in","r",stdin);freopen("3292.out","w",stdout);
    rp(i,1,60)poww[i]=poww[i-1]<<1;
    n=read();q=read();rp(i,1,n)val[i]=read();rp(i,1,n-1){ri x=read(),y=read();ad(x,y);}dfs1(1,0);dfs2(1,1);
    rp(i,2,n)lg[i]=lg[i>>1]+1;rp(j,1,lg[n])rp(i,1,n+1-poww[j])gdgs[j][i]=merg(gdgs[j-1][i],gdgs[j-1][i+poww[j-1]]);
    while(q--)
    {
        ri x=read(),y=read();as.clr();
        while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);as=merg(gt(dfn[top[x]],dfn[x]),as);x=fa[top[x]];}
        if(dep[x]<dep[y])swap(x,y);as=merg(gt(dfn[y],dfn[x]),as);printf("%lld\n",as.mx());
    }
    return 0;
}
放下代码鸭QwQ

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值