• luoguP3292 [SCOI2016]幸运数字(线性基+树上倍增)


    传送:https://www.luogu.org/problem/P3292

    题意:

    $n$座城市,$n-1$条路,每个城市有一个价值$a_i$。$q$个询问,每次询问城市$x$到城市$y$的路径上经过的城市的价值的最大异或和为多少。

    数据范围:

    $1<=n<=20000,q<=200000,a_i<=2^{60}$。

    分析:

    对于一次询问$x-->y$的路径上的答案,很明显就是$x-->lca(x,y)$的线性基并上$y-->lca(x,y)$的线性基,然后求最大异或和。

    那么对于多个询问来说怎么考虑呢?

    在一棵树上查询$lca$有两种做法:1)tarjan/dfs(离线);2)ST表+倍增(在线)。对于这个题很明显需要维护路径上的线性基,我们用第二种倍增的做法在求$lca$的同时,就可以维护线性基,然后查询答案。

    用$f[i][j]$代表点$i$向上跳$2^j$布达到哪一个点。用$LB[i][j]$代表向上$2^j$步路径上的线性基。

    然后求$lca$的过程中同时暴力合并线性基可以了鸭。(qaaaaq

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn=2e4+10;
     5 struct node{
     6     int to,nxt;
     7 }edge[maxn*2];
     8 int head[maxn],f[maxn][20],deep[maxn],tot,N,n,q;
     9 ll a[maxn];
    10 struct Linear_basis{
    11     ll b[65];
    12     bool insert(ll x){
    13         for (int i=62;i>=0;i--){
    14             if (x&(1ll<<i)){
    15                 if (!b[i]){b[i]=x; break;} 
    16                 x^=b[i];
    17             } 
    18         }
    19         return x>0;  //是否可插入 true:可插入,false:不可插入 
    20     }
    21     ll mx(){
    22         ll res=0;
    23         for (int i=62;i>=0;i--) res=max(res,res^b[i]);
    24         return res;
    25     }
    26     void clear(){
    27         memset(b,0,sizeof(b));
    28     }
    29 }LB[maxn][20],ans;
    30 void add(int x,int y){
    31     edge[++tot]={y,head[x]}; head[x]=tot;
    32 }
    33 void dfs(int x,int fa){
    34     f[x][0]=fa; //倍增数组 
    35     LB[x][0].insert(a[x]); 
    36     for (int i=head[x];i!=-1;i=edge[i].nxt){
    37         node tmp=edge[i];
    38         if (tmp.to==fa) continue;
    39         deep[tmp.to]=deep[x]+1;
    40         dfs(tmp.to,x);
    41     }
    42 }
    43 Linear_basis merge(Linear_basis p,Linear_basis q){
    44     Linear_basis tmp=p;
    45     for (int i=62;i>=0;i--){
    46         if (q.b[i]) tmp.insert(q.b[i]);
    47     }
    48     return tmp;
    49 }
    50 void init(){
    51     N=floor(log(1.0*n)/log(2.0));
    52     deep[1]=0;
    53     dfs(1,0);
    54     for (int j=1;j<=N;j++){
    55         for (int i=1;i<=n;i++){
    56             f[i][j]=f[f[i][j-1]][j-1];
    57             LB[i][j]=merge(LB[i][j-1],LB[f[i][j-1]][j-1]); 
    58         }
    59     }
    60 }
    61 int _LCA(int x,int y){
    62     if (deep[x]<deep[y]) swap(x,y);
    63     for (int j=N;j>=0;j--)
    64         if (deep[f[x][j]]>=deep[y]){
    65             ans=merge(ans,LB[x][j]);
    66             x=f[x][j];
    67         }
    68     if (x==y){
    69         ans=merge(ans,LB[x][0]); return x;
    70     }
    71     for (int j=N;j>=0;j--){
    72         if (f[x][j]!=f[y][j]){
    73             ans=merge(ans,merge(LB[x][j],LB[y][j]));
    74             x=f[x][j]; y=f[y][j];
    75         }
    76     }
    77     Linear_basis tmp=merge(LB[x][0],LB[y][0]);
    78     Linear_basis tmp2=merge(ans,LB[f[x][0]][0]);
    79     ans=merge(tmp2,tmp);
    80     return f[x][0]; //lca
    81 }
    82 int main(){
    83     scanf("%d%d",&n,&q);
    84     for (int i=1;i<=n;i++) scanf("%lld",&a[i]),head[i]=-1;
    85     int x,y; tot=0;
    86     for (int i=1;i<=n-1;i++){
    87         scanf("%d%d",&x,&y);
    88         add(x,y);add(y,x);
    89     }
    90     init();
    91     while (q--){
    92         scanf("%d%d",&x,&y);
    93         ans.clear(); 
    94         _LCA(x,y);
    95         printf("%lld
    ",ans.mx()); 
    96     }
    97     return 0;
    98 }
  • 相关阅读:
    c++深拷贝与浅拷贝
    c++构造函数的explicit
    c++虚函数和虚函数表
    c++重载、重写、隐藏(重定义)
    c++传值、传指针、传引用
    ASP.Net Core API 学习の中间件
    WPF中String Format的用法
    ASP.Net Core API 全局处理异常
    989. Add to Array-Form of Integer
    1014. Best Sightseeing Pair
  • 原文地址:https://www.cnblogs.com/changer-qyz/p/11355642.html
Copyright © 2020-2023  润新知