牛客练习赛58 F题 树链剖分 + 线段树魔改

题目传送门

题意:

给出一颗 牛客练习赛58  F题  树链剖分 + 线段树魔改 个结点的树,第 牛客练习赛58  F题  树链剖分 + 线段树魔改 个结点的权值为 牛客练习赛58  F题  树链剖分 + 线段树魔改

定义点 牛客练习赛58  F题  树链剖分 + 线段树魔改 到点 牛客练习赛58  F题  树链剖分 + 线段树魔改 的路径的长度为点 牛客练习赛58  F题  树链剖分 + 线段树魔改 到点 牛客练习赛58  F题  树链剖分 + 线段树魔改 的最短路径上的所有结点的权值的异或和。

单独一个点不算做路径。

现在要求你维护 牛客练习赛58  F题  树链剖分 + 线段树魔改 个操作:

总共有两种操作,一种是把某一个点的权值 牛客练习赛58  F题  树链剖分 + 线段树魔改 改成 牛客练习赛58  F题  树链剖分 + 线段树魔改 ,另一种是询问点 牛客练习赛58  F题  树链剖分 + 线段树魔改 到点 牛客练习赛58  F题  树链剖分 + 线段树魔改 之间的所有子路径的长度的异或和。

注意:子路径。

数据范围: 牛客练习赛58  F题  树链剖分 + 线段树魔改

题解:

很明显你要掏出树剖板子,点修改区间求和线段树板子。

然后会发现一些规律,路径上的任意点 牛客练习赛58  F题  树链剖分 + 线段树魔改 ,牛客练习赛58  F题  树链剖分 + 线段树魔改 被异或的次数是 牛客练习赛58  F题  树链剖分 + 线段树魔改 , 牛客练习赛58  F题  树链剖分 + 线段树魔改 是路径长度。

那么 牛客练习赛58  F题  树链剖分 + 线段树魔改 有贡献必须 牛客练习赛58  F题  树链剖分 + 线段树魔改 是奇数。

当 牛客练习赛58  F题  树链剖分 + 线段树魔改 是偶数时,是可以的。

当 牛客练习赛58  F题  树链剖分 + 线段树魔改 是偶数是可以的。

所以当 牛客练习赛58  F题  树链剖分 + 线段树魔改 是偶数的时候,答案是路径长度的异或和。

当 牛客练习赛58  F题  树链剖分 + 线段树魔改 是奇数的时候,答案是路径长度的异或和 异或 下标为奇数的异或和。

线段树维护区间异或和,区间内下标为奇数的异或和。

说的下标为奇数都是相对于区间而言的。

感受:

过了之后去百度搜了搜别人过了的代码,想知道有没有更简便的做法。

结果就是别人的代码长度比我的二分之一还要少。

我好菜啊。

这个真的是裸题吗,我线段树魔改了好久,还对拍了一会才过题。

这份代码用了快读比不用慢,不知道为什么。

代码:

#include<bits/stdc++.h>
using namespace std ;
typedef unsigned long long ull ;
const int maxn = 2e5 + 5 ;
int n , q ;
int num , head[maxn] ;
int w[maxn] , wt[maxn] , son[maxn] , dfn[maxn] , fa[maxn] ;
int cnt = 0 ;
int dep[maxn] , siz[maxn] , top[maxn] ;
int sum[maxn << 2] , sum1[maxn << 2] ;
struct Edge
{
    int v , next ;
} edge[maxn << 1] ;
void add_edge(int u , int v)
{
    edge[num].v = v ;
    edge[num].next = head[u] ;
    head[u] = num ++ ;
}
int read()
{
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x;
}
void dfs1(int x , int f , int deep)
{
   dep[x] = deep ;
   fa[x] = f ;
   siz[x] = 1 ;
   son[x] = 0 ;
   int maxson = -1 ;
   for(int i = head[x] ; i != -1 ; i = edge[i].next)
   {
     int y = edge[i].v ;
     if(y == f) continue ;
     dfs1(y , x , deep + 1) ;
     siz[x] += siz[y] ;
     if(siz[y] > maxson)
     son[x] = y , maxson = siz[y] ;
   }
}
void dfs2(int x , int topf)
{
   dfn[x] = ++ cnt ;
   wt[cnt] = w[x] ;
   top[x] = topf ;
   if(!son[x]) return ;
   dfs2(son[x] , topf) ;
   for(int i = head[x] ; i != -1 ; i = edge[i].next)
   {
     int y = edge[i].v ;
     if(y == fa[x] || y == son[x]) continue ;
     dfs2(y , y) ;
   }
}
int ls(int x)
{
   return x << 1 ;
}
int rs(int x)
{
   return x << 1 | 1 ;
}
void build(int id , int l , int r)
{
   if(l == r){sum1[id] = sum[id] = wt[l] ; return ;}
   int mid = (l + r) >> 1 ;
   int len = mid - l + 1 ;
   build(ls(id) , l , mid) ;
   build(rs(id) , mid + 1 , r) ;
   sum[id] = sum[ls(id)] ^ sum[rs(id)] ;
   sum1[id] = sum1[ls(id)] ;
   if(len % 2 == 0)  sum1[id] ^= sum1[rs(id)] ;
   else  sum1[id] ^= (sum[rs(id)] ^ sum1[rs(id)]) ;
}
void update(int id , int l , int r , int x , int y)
{
   int mid = (l + r) / 2 ;
   int len = mid - l + 1 ;
   if(l == r && l == x){sum1[id] = sum[id] = y ; return ;}
   if(x <= mid)  update(ls(id) , l , mid , x , y) ;
   else  update(rs(id) , mid + 1 , r , x , y) ;
   sum[id] = sum[ls(id)] ^ sum[rs(id)] ;
   sum1[id] = sum1[ls(id)] ;
   if(len % 2 == 0)  sum1[id] ^= sum1[rs(id)] ;
   else  sum1[id] ^= (sum[rs(id)] ^ sum1[rs(id)]) ;
}
int query(int id , int l , int r , int x , int y)
{
   int ans = 0 ;
   int mid = (l + r) / 2 ;
   if(x <= l && r <= y)  return sum[id] ;
   if(x <= mid)  ans ^= query(ls(id) , l , mid , x , y) ;
   if(y > mid)  ans ^= query(rs(id) , mid + 1 , r , x , y) ;
   return ans ;
}
int query1(int id , int l , int r , int x , int y , int f)
{
   int ans = 0 ;
   int mid = (l + r) / 2 ;
   if(x <= l && r <= y)
   {
      if(f == (l - x + 1) % 2)  return sum1[id] ;
      else  return sum[id] ^ sum1[id] ;
   }
   if(x <= mid)  ans ^= query1(ls(id) , l , mid , x , y , f) ;
   if(y > mid)  ans ^= query1(rs(id) , mid + 1 , r , x , y , f) ;
   return ans ;
}
void upd_range(int x , int k)
{
   update(1 , 1 , n , dfn[x] , k) ;
}
int cal1(int x , int y)
{
    int ans = 0 ;
    while(top[x] != top[y])
    {
       if(dep[top[x]] < dep[top[y]])  swap(x , y) ;
       ans ^= query(1 , 1 , n , dfn[top[x]] , dfn[x]) ;
       x = fa[top[x]] ;
    }
    if(dep[x] > dep[y])  swap(x , y) ;
    ans ^= query(1 , 1 , n , dfn[x] , dfn[y]) ;
    return ans ;
}
int cal2(int x , int y)
{
    int ans = 0 ;
    bool fx = 1 , gx ;
    bool fy , gy = 1 ;
    while(top[x] != top[y])
    {
       if(dep[top[x]] >= dep[top[y]])
       {
          int len = dep[x] - dep[top[x]] + 1 ;
          if(len % 2 == 0)  gx = !fx , fx = !gx ;
          else  gx = fx , fx = !gx ;
          ans ^= query1(1 , 1 , n , dfn[top[x]] , dfn[x] , gx) ;
          x = fa[top[x]] ;
       }
       else
       {
          int len = dep[y] - dep[top[y]] + 1 ;
          if(len % 2 == 0)  fy = !gy , gy = !fy ;
          else  fy = gy , gy = !fy ;
          ans ^= query1(1 , 1 , n , dfn[top[y]] , dfn[y] , fy) ;
          y = fa[top[y]] ;
       }
    }
    if(dep[x] < dep[y])
      ans ^= query1(1 , 1 , n , dfn[x] , dfn[y] , fx) ;
    else
      ans ^= query1(1 , 1 , n , dfn[y] , dfn[x] , gy) ;
    return ans ;
}
int lca(int x, int y)
{
   while(top[x] != top[y])
   {
     if(dep[top[x]] < dep[top[y]]) swap(x , y) ;
     x = fa[top[x]] ;
   }
   return dep[x] < dep[y] ? x : y ;
}
int q_range(int x , int y)
{
   int ans = 0 ;
   int z = lca(x , y) ;
   int len = dep[x] + dep[y] - 2 * dep[z] + 1 ;
   ans ^= cal1(x , y) ;
   if(len % 2 == 1)  ans ^= cal2(x , y) ;
   return ans ;
}
int main()
{
    //freopen("data.in","r",stdin);           
    //freopen("A.out","w",stdout);
    scanf("%d%d" , &n , &q) ;
    num = 0 ;
    memset(head , -1 , sizeof(head)) ;
    for(int i = 1 ; i <= n ; i ++)  scanf("%d" , &w[i]) ;
    for(int i = 1 ; i <= n - 1 ; i ++)
    {
        int u , v ;
        scanf("%d%d" , &u , &v) ;
        add_edge(u , v) ;
        add_edge(v , u) ;
    }
    dfs1(1 , 0 , 1) ;
    dfs2(1 , 1) ;
    build(1 , 1 , n) ;
    vector<int> h ;
    while(q --)
    {
        int op , a , b ;
        scanf("%d%d%d" , &op , &a , &b) ;
        if(op == 1)  upd_range(a , b) ;
        else  printf("%d\n" , q_range(a , b)) ;
    }
    return 0 ;
}

 

牛客练习赛58  F题  树链剖分 + 线段树魔改牛客练习赛58  F题  树链剖分 + 线段树魔改 敲代码的欧文 发布了244 篇原创文章 · 获赞 12 · 访问量 1万+ 私信 关注
上一篇:深度优先搜索和广度优先搜索


下一篇:luogu6584 重拳出击