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

本文介绍了一种涉及树链剖分与线段树优化的技术问题解决方法,针对1e5规模的节点树,提出了两种高效的算法实现方案。方法一利用线段树维护每个节点到根节点的异或值,通过查询来判断路径上的权值是否为偶数个;方法二采用树链剖分技术,同样达到高效查询的目的。
摘要由CSDN通过智能技术生成

Problem Description
Dylans is given a tree with N nodes.

All nodes have a value A[i] .Nodes on tree is numbered by 1N .

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.

1N,Q100000 , the value A[i]N and A[i]100000
 

Input
In the first line there is a test number T .
( T3 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 N1 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
 


大致题意:

一棵树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);
            }
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值