hdu 5274 Dylans loves tree

Dylans loves tree

http://acm.hdu.edu.cn/showproblem.php?pid=5274

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

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
 
题目大意:给出一颗n个点的树,有q个操作,点有点权。
操作① 0,x,y 修改x的点权为y
操作② 1,x,y 询问点x到点y是否有出现过奇数次的权值,有则输出,无则输出-1。输入保证至多有一个出现过一次的权值
基本框架:树链剖分+线段树
思路:单点修改+询问区间异或和
若k出现过偶数次,则这些k的异或和为0
若只有1个k出现过奇数次,那异或的结果=k
一个小细节:
因为0无论异或多少次都是0,所以将所有数都+1,输出答案-1
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100001
using namespace std;
struct node
{
    int l,r,key;
    void clear() {l=r=key=0;}
}tr[N*2];
struct edge{int next,to;}e[N*2];
int id[N],dep[N],son[N],fa[N],bl[N],sz,e_tot,tr_tot,T,n,q,head[N];
inline void add(int u,int v)
{
    e[++e_tot].to=v;e[e_tot].next=head[u];head[u]=e_tot;
    e[++e_tot].to=u;e[e_tot].next=head[v];head[v]=e_tot;
}
inline void dfs1(int x,int f)
{
    son[x]++;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==fa[x]) continue;
        dep[e[i].to]=dep[x]+1;
        fa[e[i].to]=x;
        dfs1(e[i].to,x);
        son[x]+=son[e[i].to];
    }
} 
inline void dfs2(int x,int chain)
{
    sz++;
    bl[x]=chain;
    id[x]=sz;
    int y=0;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==fa[x]) continue;
        if(son[e[i].to]>son[y]) y=e[i].to;
    }
    if(!y) return;
    dfs2(y,chain);
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==fa[x]||e[i].to==y) continue;
        dfs2(e[i].to,e[i].to);
    }
}
inline void build(int l,int r)
{
    tr_tot++; tr[tr_tot].clear();
    tr[tr_tot].l=l;tr[tr_tot].r=r;
    if(l==r) return;
    int mid=l+r>>1;
    build(l,mid);build(mid+1,r);
}
inline void change(int k,int x,int w)
{
    if(tr[k].l==tr[k].r) {tr[k].key=w;return;}
    int mid=tr[k].l+tr[k].r>>1,l=k+1,r=k+(tr[k+1].r-tr[k+1].l+1<<1);
    if(x<=mid) change(l,x,w);
    else change(r,x,w);
    tr[k].key=tr[l].key^tr[r].key;
}
inline int query(int k,int opl,int opr)
{
    if(tr[k].l>=opl&&tr[k].r<=opr) {return tr[k].key;}
    int mid=tr[k].l+tr[k].r>>1,l=k+1,r=k+(tr[k+1].r-tr[k+1].l+1<<1);
    int tmp=0;
    if(opl<=mid) tmp=query(l,opl,opr);
    if(opr>mid) tmp^=query(r,opl,opr);
    return tmp;
}
inline void solve_query(int u,int v)
{
    int ans=0;
    while(bl[u]!=bl[v])
    {
        if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
        ans^=query(1,id[bl[u]],id[u]);
        u=fa[bl[u]];
    }
    if(id[u]>id[v]) swap(u,v);
    ans^=query(1,id[u],id[v]);
    printf("%d\n",ans-1);
}
inline void solve()
{
    int p,x,y;
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&x);
        change(1,id[i],x+1);
    }
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d%d",&p,&x,&y);
        if(!p) change(1,id[x],y+1);
        else solve_query(x,y);
    }
}
inline void pre()
{
    memset(son,0,sizeof(son));
    memset(head,0,sizeof(head));
    memset(fa,0,sizeof(fa));
    memset(dep,0,sizeof(dep));
    sz=e_tot=tr_tot=0;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        pre();
        scanf("%d%d",&n,&q);
        int u,v;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        dfs1(1,0);
        dfs2(1,1);
        build(1,n);
        solve();
    }
}

 

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/6403314.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值