hdu 5274 Dylans loves tree (树链剖分+异或和)

21 篇文章 0 订阅
6 篇文章 0 订阅

Dylans loves tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1881    Accepted Submission(s): 477


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
 
 
13 21 22 31 1 11 1 21 1 3
 
Sample Output
 
 
-11
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.
 


题意:

给你一棵树,n-1条边,每个点的权值,还有q个询问,

当询问id==0时,改变x点的权值为y

id==1时,输出x->y路径上,权值出现奇数次的权值(题目保证这个答案最多只有1个)


解析:

首先这里用树链剖分优化

这里有奇数次,且答案保证唯一,刚好满足异或的性质所以我们只要维护异或和的线段树就可以了。

并且这里答案为0时存在特殊情况,要处理一下

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int MAXN = 1e5+10;
const int ZERO = 1000001;
#define INF 1147483647
#define M(a) memset(a,0,sizeof(a))
int val[MAXN],fa[MAXN],dep[MAXN],siz[MAXN],id[MAXN],top[MAXN],ran[MAXN],son[MAXN];

typedef struct ee
{
    int u,v;
    int next;
}ee;

ee edge[MAXN*2];
int head[MAXN],cnt;
int num,n;

typedef struct node
{
    int ii;
    int sum;
}node;

node Btree[MAXN*4];

void addedge(int u,int v)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

void dfs1(int x,int f,int d)
{
    dep[x]=d;
    siz[x]=1;
    son[x]=0;
    fa[x]=f;
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int tmp=edge[i].v;
        if(tmp==f) continue;
        dfs1(tmp,x,d+1);
        siz[x]+=siz[tmp];
        if(siz[son[x]]<siz[tmp])
        {
            son[x]=tmp;
        }
    }
}

void dfs2(int x,int tp)
{
    top[x]=tp;
    id[x]=++num;
    ran[num]=x;
    if(son[x]) dfs2(son[x],tp);
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int tmp=edge[i].v;
        if(tmp==fa[x]||tmp==son[x]) continue;
        dfs2(tmp,tmp);
    }

}

void Pushup(int root)
{
    Btree[root].sum=Btree[2*root].sum^Btree[2*root+1].sum;
}

void build(int stu[],int l,int r,int root)
{
    if(l>r) return;
    if(l==r)
    {
        Btree[root].ii=l;
        Btree[root].sum=stu[ran[l]];
        return;
    }

    int mid=(l+r)/2;
    build(stu,l,mid,root*2);
    build(stu,mid+1,r,root*2+1);

    Pushup(root);
}

void update(int root,int l,int r,int index,int val)
{
    if(l>r) return;
    if(l==r)
    {
        if(l==index)
        {
            Btree[root].sum=val;
        }
        return;

    }

    int mid=(l+r)/2;
    if(index<=mid)
        update(root*2,l,mid,index,val);
    else
        update(root*2+1,mid+1,r,index,val);

    Pushup(root);
}



int querysum(int root,int l,int r,int s,int e)
{
    if(r<s||l>e)
    {
        return 0;
    }
    if(l>r) return 0;
    if(s<=l&&r<=e)
    {
        return Btree[root].sum;
    }
    int mid=(l+r)/2;

    int lan=querysum(2*root,l,mid,s,e);
    int ran=querysum(root*2+1,mid+1,r,s,e);

    return lan^ran;
}




int solvesum(int a,int b)
{
    if(dep[top[a]]<dep[top[b]])
    {
        swap(a,b);
    }
    int ans=0;
    while(top[a]!=top[b])
    {
        //int tmp=top[a];
        ans^=querysum(1,1,n,id[top[a]],id[a]);
        a=fa[top[a]];
        if(dep[top[a]]<dep[top[b]])
        {
            swap(a,b);
        }
    }
    if(id[a]>id[b]) swap(a,b);
    ans^=querysum(1,1,n,id[a],id[b]);
    if(ans==ZERO) printf("0\n");
    else if(ans==0) printf("-1\n");
    else printf("%d\n",ans);
}


int main()
{
    int q,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&q);
        num=0;
        M(Btree);
        M(son);
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
            if(val[i]==0) val[i]=ZERO;
        }
        dfs1(1,0,1);
        dfs2(1,1);
        int mode,a,b;
        build(val,1,n,1);
        for(int i=0;i<q;i++)
        {
            scanf("%d%d%d",&mode,&a,&b);
            if(mode==0)
            {
                val[a]=b;
                update(1,1,n,id[a],b);
            }
            else if(mode==1)
            {
                solvesum(a,b);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值