BestCoder #45 1003 Dylans loves tree

problem


题意

  • 给定一棵树,并给定在这棵树上的两种操作。一种操作是改变一个节点的权值,另外一个操作是对两个节点之间的路径上的权值进行统计,如果每个权值出现的次数都是偶数,输出-1,否则输出出现次数为奇数的权值(保证只有一个)

思路

  • 这题是一个DFS序的模板题。首先想到,我们获得这棵树的DFS序,对于这个序列,我们可以去维护区间的异或和。由于是单点修改区间查询,可以用树状数组也可以直接写线段树。然后对于每个询问,我们查询出每个点到根的异或和(这里直接用DFS序中到根节点的异或和即可,因为如果一个结点不在其到根节点的路径上,其会出现两次,异或和为0),然后求出这两个结点的LCA,再异或LCA的权值。注意这个地方,如果一个结点权值为0,会出错。所以这里要进行处理(把权值都加1,输出答案的时候减1)。LCA用倍增法、Tarjan、RMQ都可以。
  • 这题HDU略坑,交G++一直爆栈。然而没必要去管这个。。交C++就过了。

AC代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAXN = 110000;
int cnt,head[MAXN],dep[MAXN],p[MAXN][20],tot;
int st[MAXN],ed[MAXN];
int sum[MAXN<<3];
int n,q;
void update(int pos,int c,int l,int r,int rt){
    if(l == r){
        sum[rt] = c;
        return;
    }
    int m = (l+r)>>1;
    if(pos <= m)update(pos,c,lson);
    else update(pos,c,rson);
    sum[rt] = sum[rt<<1] ^ sum[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt){
    if(l>=L && R>=r){
        return sum[rt];
    }
    int ret = 0;
    int m = (l+r)>>1;
    if(L <= m)ret ^= query(L,R,lson);
    if(R > m)ret ^= query(L,R,rson);
    return ret;
}
struct Edge{
    int u,v;
    int next;
}e[MAXN<<1];
void addedge(int u,int v){
    e[cnt].u = u,e[cnt].v = v,e[cnt].next = head[u],head[u] = cnt++;
    e[cnt].u = v,e[cnt].v = u,e[cnt].next = head[v],head[v] = cnt++;
}
void dfs(int u){
    st[u] = tot++;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v = e[i].v;
        if(!dep[v]){
            dep[v] = dep[u] + 1;
            p[v][0] = u;
            dfs(v);
        }
    }
    ed[u] = tot++;
}
void init(){
    cnt = 0;
    tot = 1;
    memset(head,-1,sizeof(head));
    memset(p,-1,sizeof(p));
    memset(dep,0,sizeof(dep));
}
int LCA(int a,int b){
    if(dep[a]<dep[b])swap(a,b);
    int i;
    for(i = 0;(1<<i)<=dep[a];i++);
    i--;
    for(int j=i;j>=0;j--)
        if(dep[a]-(1<<j)>=dep[b])
            a = p[a][j];
    if(a == b)return a;
    for(int j=i;j>=0;j--){
        if(p[a][j]!=-1 && p[a][j] != p[b][j]){
            a = p[a][j];
            b = p[b][j];
        }
    }
    return p[a][0];
}
int u,v;
int main()
{
    int T;
    cin>>T;
    while(T--){
        scanf("%d%d",&n,&q);
        init();
        for(int i=0;i<n-1;i++){
            scanf("%d%d",&u,&v);
            addedge(u,v);
        }
        dep[1] = 1;
        dfs(1);
        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i<=n;i++)
                if(p[i][j-1] != -1)
                    p[i][j] = p[p[i][j-1]][j-1];
        tot--;
        memset(sum,0,sizeof(sum));
        //for(int i=1;i<=n;i++)printf("%d ",st[i]);
        //printf("tot : %d\n",tot);
        for(int i=1;i<=n;i++){
            scanf("%d",&u);
            update(st[i],u+1,1,tot,1),update(ed[i],u+1,1,tot,1);
        }
        while(q--){
            int op,x,y;
            scanf("%d%d%d",&op,&x,&y);
            if(op == 0){
                update(st[x],y+1,1,tot,1),update(ed[x],y+1,1,tot,1);
            }else{
                int ansx = query(1,st[x],1,tot,1),ansy = query(1,st[y],1,tot,1);
                int lca = LCA(x,y),anslca =query(st[lca],st[lca],1,tot,1);
                //printf("ansx:%d ansy:%d lca:%d\n",ansx,ansy,lca);
                int ans = ansx ^ ansy ^ anslca;
                if( ans == 0)puts("-1");
                else printf("%d\n",ans-1);
            }
        }
    }
    return 0;
}
时间: 2024-10-20 13:02:46

BestCoder #45 1003 Dylans loves tree的相关文章

AC日记——Dylans loves tree hdu 5274

Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1611    Accepted Submission(s): 388 Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i] .Node

HDU5274 Dylans loves tree(树链剖分)很巧的点权更新

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

(bc #45) A - Dylans loves numbers (hdu 5272)

Dylans loves numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 569    Accepted Submission(s): 320 Problem Description Who is Dylans?You can find his ID in UOJ and Codeforces.His another

HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)

Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes on tree is numbered by 1∼N. Then he is given Q questions like that: ①0 x y:change node x′s value to y ②1 x y:For all the value in the path from x to y,do they

hdu5274 Dylans loves tree LCA+线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5274 在树上的询问和操作,每次修改单点值,询问两点之间出现次数为奇数的点权是什么,若没有输出-1.询问保证两点间至多只有一个数出现奇数次. 有一种经典的将树上的点转化成序列的方法,我们用dfs遍历这棵树,那么对于一个节点,他一点比他的子树即子节点先访问到,且当他的最后一个子节点的所有子树也都访问完时,这中间访问的节点一定都是他的子树.那么我们可以在访问时做一下记录,每个点首先被访问的clock,和结束时

HDU5274 Dylans loves tree(树链剖分+异或)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5274 题意很简单,输入以后,查询的时候 0 x y,是把x点改成y. 1 x y,是查询[x,y]中,数字出现的次数是否都是偶数,出现奇数的数字<=1. 都是偶数的话,输出-1,有奇数的话,输出奇数的权值. 思路:这题也是一个裸题,但是这题的线段树维护的比较巧妙,因为一个数异或自己偶数次就是0,所以求一个区间异或和就行了.但是有个地方要注意,就是权值为0的话,异或自己,奇数次也是0.所以可以把所有的权

Dylans loves tree

\(trick\) 如果有3个点,权值都为0,尽管异或为0,但0是出现了奇数次,应该输出0.... \(code\) 树剖模板 const int N = 100005; int n, q, tot, cnt; int head[N], pa[N], dep[N], sz[N], son[N], top[N], id[N], rk[N]; struct node { int to, next; } e[N * 2]; void Inite() { cnt = tot = 0; mem(head,

【BestCoder #45】

用家里的电脑来编程,各种不算 一开始15分钟刷掉T1和T2,然后就永远地卡在了T3... 后来看题解,傻了眼... 它强调的“只有一个答案”我还以为这是在提示我二分答案,于是我一直往权值线段树那个方向想去 哪知它还代表一个意思:路径xor值即是答案... 好吧我脑袋秀逗了.. 代码: T1 #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #define r

从lca到树链剖分 bestcoder round#45 1003

bestcoder round#45 1003 题,给定两个点,要我们求这两个点的树上路径所经过的点的权值是否出现过奇数次.如果是一般人,那么就是用lca求树上路径,然后判断是否出现过奇数次(用异或),高手就不这么做了,直接树链剖分.为什么不能用lca,因为如果有树退化成链,那么每次询问的复杂度是O(n), 那么q次询问的时间复杂度是O(qn) 什么是树链剖分呢? 就是把树的边分成轻链和重链 http://blogsina.com.cn/s/blog_6974c8b20100zc61.htmlh