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 xs
value to y

②1 x y:For
all the value in the path from x
to y,do
they all appear even times?

For each ② question,it guarantees that there is at most one value that appears odd times on the path.

1≤N,Q≤100000,
the value A[i]∈N
and A[i]≤100000

Input

In the first line there is a test number
T.

(T≤3
and there is at most one testcase that N>1000)

For each testcase:

In the first line there are two numbers N
and Q.

Then in the next N?1
lines there are pairs of (X,Y)
that stand for a road from x
to y.

Then in the next line there are N
numbers A1..AN
stand for value.

In the next Q
lines there are three numbers(opt,x,y).

Output

For each question ② in each testcase,if the value all appear even times output "-1",otherwise output the value that appears odd times.

Sample Input

1
3 2
1 2
2 3
1 1 1
1 1 2
1 1 3

Sample Output

-1
1

Hint

If you want to hack someone,N and Q in your testdata must smaller than 10000,and you shouldn‘t print any space in each end of the line.

Source

BestCoder Round #45

大致题意:

一棵树1e5节点的树,有1e5次两种操作,修改某点的权值,询问两点间的路径上的每个权值是否都是偶数个,若不是输出奇数个的权值大小,保证询问的路径上最多只有一个权值是奇数个

思路:

方法1.维护每个点到根的异或,然后查询就是xor[u]^xor[v]^LCA(u,v)

更新操作:更新某个点显然此点的子树的xor到根的异或都会更新,所以用dfs记录进入节点和退出节点的时间戳,把时间戳作为节点映射到线段树上(所以个数是数节点的两倍),然后成段更新进入此节点到退出此节点的时间戳的区间即可

复杂度是nlogn

方法2:

正面上,询问就是两个点间的路径的异或,即树链剖分

复杂度n*logn*logn

方法一:

#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
using namespace std;
typedef long long ll;

const int N = 1e5+100;
int n,Q;
int indx;
struct Edge
{
    int v,nxt;
    Edge(){}
    Edge(int v,int nxt):v(v),nxt(nxt){}
}es[N<<1];
int head[N],ecnt;
inline void add_edge(int v,int u)
{
    es[ecnt] = Edge(v,head[u]);
    head[u] = ecnt++;
    es[ecnt] = Edge(u,head[v]);
    head[v] = ecnt++;
}
int val[N];
//....................................
#define root 1,indx,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int XOR[N<<2];
inline void pushup(int rt)
{
    XOR[rt] = XOR[rt<<1]^XOR[rt<<1|1];
}
void update(int pos,int x,int l,int r,int rt)
{
    if(l == r)
    {
        XOR[rt] ^= x;
        return ;
    }
    int m = (l+r)>>1;
    if(pos <= m) update(pos,x,lson);
    else update(pos,x,rson);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R) return XOR[rt];
    int m = (l+r)>>1;
    int ans = 0;
    if(L <= m) ans ^= query(L,R,lson);
    if(R > m) ans ^= query(L,R,rson);
    return ans;
}
//.................................
int dep[N],hvyson[N],sz[N],fa[N];
void dfs1(int u)
{
    dep[u] = dep[fa[u]]+1;
    hvyson[u] = 0,sz[u] = 1;
    for(int i = head[u];~i;i = es[i].nxt)
    {
        int v = es[i].v;
        if(v == fa[u]) continue;
        fa[v] = u;
        dfs1(v);
        sz[u] += sz[v];
        if(sz[v] > sz[hvyson[u]]) hvyson[u] = v;
    }
}
int tp[N],tid[N];
void dfs2(int u,int ance)
{
    tid[u] = ++indx;
    tp[u] = ance;
    if(hvyson[u]) dfs2(hvyson[u],ance);
    for(int i = head[u];~i;i = es[i].nxt)
    {
        int v = es[i].v;
        if(v == fa[u]) continue;
        if(v != hvyson[u])dfs2(v,v);
    }
}
int ask(int u,int v)
{
    int anceu = tp[u],ancev = tp[v];
    int ans = 0;
    while(anceu != ancev)
    {
        if(dep[anceu] < dep[ancev]) swap(anceu,ancev),swap(u,v);
        ans ^= query(tid[anceu],tid[u],root);
        u = fa[anceu];
        anceu = tp[u];
    }
    if(u == v) return ans ^= val[u];
    if(dep[u] < dep[v]) return ans ^= query(tid[u],tid[v],root);
    else return ans ^= query(tid[v],tid[u],root);
}
//..................................
void ini()
{
    ecnt = indx = 0;
    memset(head,-1,sizeof(head));
    memset(XOR,0,sizeof(XOR));
}
int main()
{

    int T;
    scanf("%d",&T);
    while(T--)
    {
        ini();
        scanf("%d%d",&n,&Q);
        REP(i,n-1)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        REP(i,n) scanf("%d",&val[i]),val[i]++;
        dfs1(1);
        dfs2(1,1);
        REP(i,n) update(tid[i],val[i],root);
        REP(i,Q)
        {
            int op;
            scanf("%d",&op);
            if(op == 0)
            {
                int u,x;
                scanf("%d%d",&u,&x);x++;
                update(tid[u],val[u]^x,root);
                val[u] = x;
            }
            else
            {
                int u,v;
                scanf("%d%d",&u,&v);
                printf("%d\n",ask(u,v)-1);
            }
        }
    }
}

方法二:

//312MS 21660K 4306 B C++
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
using namespace std;
typedef long long ll;

const int N = 1e5+100;
int n,Q;
struct Edge
{
    int v,nxt;
    Edge(){}
    Edge(int v,int nxt) : v(v),nxt(nxt){}
}es[N*2];
int ecnt,head[N];
inline void add_edge(int u,int v)
{
    es[ecnt] = Edge(v,head[u]);
    head[u] = ecnt++;
    es[ecnt] = Edge(u,head[v]);
    head[v] = ecnt++;
}
int val[N];
//...................................

int indx,st[N],ed[N],vs[N<<1];
int dp[N];
void dfs(int u,int fa)
{
    dp[u] = dp[fa]^val[u];
    st[u] = ++indx;
    vs[indx] = u;
    for(int i = head[u];~i;i = es[i].nxt)
    {
        int v = es[i].v;
        if(v == fa) continue;
        dfs(v,u);
    }
    ed[u] = ++indx;
    vs[indx] = u;
}

//...............................

int dep[N];
bool vis[N];
int pa[N][20];
void bfs()
{
    queue<int>q;
    q.push(1);
    pa[1][0]=1;
    vis[1]=1;
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=1;i<20;i++) pa[u][i]=pa[pa[u][i-1]][i-1];
        for(int i=head[u];~i;i=es[i].nxt)
        {
            int v=es[i].v;
            if(vis[v]==0)
            {
                vis[v]=1;
                pa[v][0]=u;
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
}

int LCA(int u,int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    for(int det=dep[v]-dep[u],i=0;det;i++,det>>=1)
        if(det&1) v=pa[v][i];
    if(v==u) return v;
    for(int i=20-1;i>=0;i--)
        if(pa[u][i]!=pa[v][i]) v=pa[v][i],u=pa[u][i];
    return pa[u][0];
}
//...............................
int XOR[(N<<1)<<2],col[(N<<1)<<2];
#define root 1,indx,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

inline void pushup(int rt)
{
    XOR[rt] = XOR[rt<<1]^XOR[rt<<1|1];
}
inline void pushdown(int rt)
{
    if(col[rt] == 0) return ;
    col[rt<<1] ^= col[rt];
    col[rt<<1|1] ^= col[rt];
    XOR[rt<<1] ^= col[rt];
    XOR[rt<<1|1] ^= col[rt];
    col[rt] = 0;
}
void build(int l,int r,int rt)
{
    if(l == r)
    {
        XOR[rt] = dp[vs[l]];
        col[rt] = 0;
        return ;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void update(int L,int R,int x,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
        XOR[rt] ^= x;
        col[rt] ^= x;
        return ;
    }
    pushdown(rt);
    int m = (l+r)>>1;
    if(L <= m) update(L,R,x,lson);
    if(R > m) update(L,R,x,rson);
    pushup(rt);
}
int query(int pos,int l,int r,int rt)
{
    if(l == r) return XOR[rt];
    pushdown(rt);
    int m = (l+r)>>1;
    if(pos <= m) return query(pos,lson);
    else return query(pos,rson);
}
//..............................
void ini()
{
    indx = ecnt = 0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ini();
        scanf("%d%d",&n,&Q);
        REP(i,n-1)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        REP(i,n) scanf("%d",&val[i]),val[i]++;
        dfs(1,0);
        bfs();
        build(root);
        while(Q--)
        {
            int op;
            scanf("%d",&op);
            if(op == 0)
            {
                int u,x;
                scanf("%d%d",&u,&x);
                x++;
                update(st[u],ed[u],val[u]^x,root);
                val[u] = x;
            }
            else
            {
                int u,v;
                scanf("%d%d",&u,&v);
                int ans = query(ed[u],root)^query(ed[v],root)^val[LCA(u,v)];
                printf("%d\n",ans-1);
            }
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-02 15:30:31

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

hdu5274 Dylans loves tree LCA+线段树

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

HDU 3966 Aragorn&#39;s Story (树链剖分+线段树)

题意:给你一棵树,然后有三种操作 I L R K: 把L与R的路径上的所有点权值加上K D L R K:把L与R的路径上的所有点权值减去K Q X:查询节点编号为X的权值 思路:树链剖分裸题(我还没有怎么学懂,但基本已经没有什么太大的问题,主要的问题就在于点或者边对于数据结构的映射关系是,主要没有单独手写过树链剖分,所以对这部分 没有什么体会) 我们知道树链剖分是一种将树剖为链的一种算法,其思想和dfs序差不多,但根据树链剖分的性质,我们的重链是连续的区间,这样对于重链或者重链上的点我们可以方便

LCA 倍增||树链剖分

方法1:倍增 1498ms #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; typedef long long ll; const int N=5e5+5; inline int read(){ char c=getchar();int x=0,f=1; while

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路径上的每一种点权,是否都出现偶数次? 保证每次询问的路径上最多只

hdu 4929 Another Letter Tree(LCA+DP)

hdu 4929 Another Letter Tree(LCA+DP) 题意:有一棵树n个节点(n<=50000),树上每个节点上有一个字母.m个询问(m<=50000),每次询问一个(a,b),问a节点到b节点的点不重复路径组成的字符串中子序列为s0的情况有多少种,s0长度小于等于30(注意s0是已经给定的,而不是每次询问都会给出一个新的). 解法:一个很直观的想法,求出lca(设其为w)后,枚举x,求出a到w的路径上,能匹配s0的x长度前缀的情况有多少种,令其为c[x].再求出b到w的路

Water Tree(树链剖分+dfs时间戳)

Water Tree http://codeforces.com/problemset/problem/343/D time limit per test 4 seconds memory limit per test 256 megabytes input standard input output standard output Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Ea

hdu 5274 树链剖分

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

hdu 4912 Paths on the tree(树链剖分+贪心)

题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道,要求尽量选出多的通道,并且两两通道不想交. 解题思路:用树链剖分求LCA,然后根据通道两端节点的LCA深度排序,从深度最大优先选,判断两个节点均没被标 记即为可选通道.每次选完通道,将该通道LCA以下点全部标记. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include