hdu 5274 Dylans loves tree && BestCoder Round #45

题意:

Dylans loves tree

 
 Accepts: 37
 
 Submissions: 262
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
Dylans有一棵
   
   
    
    N
   
   个点的树。每个点有点权。树上节点标号为
   
   
    
    1N
   
   。
他得到了
   
   
    
    Q
   
   个询问,形式如下:
①
   
   
    
    0 x y
   
   :把第
   
   
    
    x
   
   个点的点权修改为
   
   
    
    y
   
   。
②
   
   
    
    1 x y
   
   :对于
   
   
    
    xy
   
   路径上的每一种点权,是否都出现偶数次?
保证每次询问的路径上最多只有一种点权的出现次数是奇数次。


   
   
    
    1N,Q100000
   
   , 点权
   
   
    
    A[i]N
   
   ,且都 
   
   
    
    100000
   
   
输入描述
第一行一个正整数
   
   
    
    T
   
   表示数据组数(
   
   
    
    T3
   
   且最多只有一组数据
   
   
    
    N>1000
   
   )
第一行两个数
   
   
    
    NQ
   
   表示树的点数和询问个数。
接下来
   
   
    
    N1
   
   行每行一对数
   
   
    
    (x,y)
   
   表示树上的一条边。
接下来一行
   
   
    
    N
   
   个数表示每个点的点权。
接下来
   
   
    
    Q
   
   行每行三个数
   
   
    
    (opt,x,y)
   
   表示询问。
输出描述
对于每个②询问,如果全是偶数输出“-1",否则输出出现奇数次的权值。

题解:

1.官方题解很清楚,这里想说一下把一棵树转化成一条线的方法

2.挑战程序设计竞赛上看到的转化方法,让边权重,沿叶子方向是正,逆着是负,往返的地方就自然抵消了

3.把一颗树拉成直线就可以用树状数组来做了。

总结:

1.写这个题目的时候总怕自己做不出来,觉得可能得用树链剖分啥的,然后自己不会,就不想做了,也可能是自己最

近的状态真是不佳,总是很颓废的打游戏,振作起来,争取大学期间能够在编程之美的比赛上晋级决赛!

2.依旧是那句话,相信这个题目没有错,相信自己能够做出来,攻无不克,战无不胜

3.这道题也验证了,先静态查错,debug的速度会更快一些

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define MAXM 300005
#define LOG 19
#define lowbit(i) (i & -i)
vector<int>vec[MAXN];
int _,n,q,cnt;
int val[MAXN],uid[MAXN],vid[MAXN],dp[LOG][MAXM],pre[MAXM];
void modify(int i,int v)
{
    for(;i < MAXM;i += lowbit(i))
        pre[i] ^= v;
}
int sum(int i)
{
    int ans = 0;
    for(;i;i -= lowbit(i))
        ans ^= pre[i];
    return ans;
}
void dfs(int u,int fa)
{
    for(int i = 0;i < vec[u].size();i++)
    {
        int v = vec[u][i];
        if(v == fa)continue;
        uid[v] = ++cnt;
        modify(cnt,val[v]);
        dp[0][cnt] = v;
        dfs(v,u);
        vid[v] = ++cnt;
        modify(cnt,val[v]);
        dp[0][cnt] = u;
    }
}
void init_rmq()
{
    for(int i = 1;(1 << i) <= cnt;i++)
        for(int j = 1;j + (1 << i) - 1 <= cnt;j++)
            dp[i][j] = min(dp[i - 1][j],dp[i - 1][j + (1 << i - 1)]);
}
int lca(int l,int r)
{
    if(l > r)swap(l,r);
    int i = 0;
    for(;l + (1 << i) - 1 <= r;i++);
    i--;
    return min(dp[i][l],dp[i][r - (1 << i) + 1]);
}
int main()
{
    scanf("%d",&_);
    while(_--)
    {
        scanf("%d%d",&n,&q);
        for(int i = 0;i <= n;i++)vec[i].clear();
        vec[0].push_back(1) , vec[1].push_back(0);
        memset(pre,0,sizeof(pre));
        for(int i = 1;i < n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            vec[u].push_back(v),vec[v].push_back(u);
        }
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&val[i]);
            val[i]++;
        }
        cnt = 0;
        dfs(0,-1);
        init_rmq();
        for(int i = 0;i < q;i++)
        {
            int c,u,v;
            scanf("%d%d%d",&c,&u,&v);
            if(c == 0)
            {
                v++;
                modify(uid[u],val[u] ^ v);
                modify(vid[u],val[u] ^ v);
                val[u] = v;
            }
            else
            {
                int fa = lca(uid[u],uid[v]);
                int ans = sum(uid[u]) ^ sum(uid[v]) ^ val[fa];
                if(!ans)puts("-1");
                else printf("%d\n",ans - 1);
            }
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值