• bzoj2819 nim (树上带修改查询路径异或和)


    题目简述:

    给定一棵树,n个节点,每个节点表示一个石子堆。有m个操作,操作分两种,第一种修改节点中石子数量,第二种查询两个节点路径上的所有石子堆玩nim游戏,是否必胜。

    数据范围:n,m<=500000,石子堆数量<=int_max

    分析:

    首先需要知道,nim游戏的必胜局面是石子堆的异或和不为0。基于以下性质,可以证明。

    1.石子全部取完为必败局面,其异或和为0.

    2.任意异或和不为0的局面,存在一种取法,能够转化为异或和为0的局面。

    3.任意异或和为0的局面,无论如何取,都将转化为异或和不为0的局面。

    于是原问题转换为求路径上的石子堆异或和。

    方法一:使用链剖求lca,并利用线段树或树状数组维护重链上的异或和,则可以在log2(n)的时间内完成一次查询。

    方法二:先做dfs处理,得到一个dfs序列,序列中每个节点出现两次,入栈一次,出栈一次,在任意子树在dfs序列中均为一段连续区间。

    对dfs序列使用树状数组维护前缀异或和。

    使用倍增处理任意两点的lca。

    查询路径(u,v)的异或和,即为getsum(st[u])^getsum(st[v])^stone[lca[u,v]]

    其中st[u]表示节点u在dfs序列中第一次出现的位置。

    修改节点u的石子数,即可update(st[u],stone[u]),update(ed[u]+1,stone[u]),update(st[u],newvalue),update(ed[u]+1,newvalue)

    时间复杂度为O(MlogN).但常数略大。似乎比第一种方法要慢些。

    由于担心爆栈,故写了手动栈。

    方法一:链剖求lca,使用了bfs。发现一次bfs即可,代替了原来的两次dfs写法。
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    #define MAXN 500005
    int fir[MAXN],nxt[MAXN<<1],edge[MAXN<<1],fa[MAXN],son[MAXN],depth[MAXN],pos[MAXN],maxson[MAXN],sz[MAXN],top[MAXN];
    #define lowbit(x) (x&-x)
    int stone[MAXN],xorarr[MAXN];
    int que[MAXN<<1],head,tail,ecnt;
    bool vis[MAXN];
    int n,k,q;
    char opt[3];
    void getnum(int &t)
    {
        char c;
        t=0;
        int flag=1;
        while(c=getchar(),(c>'9'||c<'0'))if(c=='-')flag=-1;
        while(c>='0'&&c<='9'){t=t*10+c-48;c=getchar();}
        t*=flag;
    }
    void adde(int a,int b)
    {
        ecnt++;
        edge[ecnt]=b,nxt[ecnt]=fir[a],fir[a]=ecnt;
        ecnt++;
        edge[ecnt]=a,nxt[ecnt]=fir[b],fir[b]=ecnt;
    }
    void insert(int id,int num)
    {
      while(id<=n)
      {
        xorarr[id]^=num;
        id+=lowbit(id);
      }
    }
    void bfs(int x)
    {
        que[tail++]=x;
        depth[x]=1;
        fa[x]=0;
        while(head<tail)
        {
            int t=que[head++];
            for(int i=fir[t];i;i=nxt[i])
            {
                int v=edge[i];
                if(v!=fa[t])
                {
                    depth[v]=depth[t]+1;
                    fa[v]=t;
                    que[tail++]=v;
                }
            }
        }
        for(int i=tail-1;i>=0;i--)
        {
          sz[que[i]]++;
          if(i==0)break;
          sz[fa[que[i]]]+=sz[que[i]];
          if(sz[que[i]]>maxson[fa[que[i]]])
            maxson[fa[que[i]]]=sz[que[i]],son[fa[que[i]]]=que[i];
        }
        int k=0;
        for(int i=0;i<tail;i++)
        {
          int t=que[i];
          if(vis[t]==1)continue;
          top[t]=t;
          while(t)
          {
              vis[t]=1;
              //xorarr[++k]=t;
              insert(++k,stone[t]);
              pos[t]=k;
              t=son[t];
              if(t)top[t]=top[fa[t]];
          }
        }
    }
    
    int getsum(int id)
    {
        int sum=0;
        while(id>0)
        {
            sum^=xorarr[id];
            id-=lowbit(id);
        }
        return sum;
    }
    int query(int u,int v)
    {
        int tmp=0;
        while(top[v]!=top[u])
        {
        	if(depth[top[v]]>depth[top[u]])swap(u,v);
          tmp^=getsum(pos[top[u]]-1);
          tmp^=getsum(pos[u]);
          u=fa[top[u]];
        }
        if(depth[v]>depth[u])swap(u,v);
        tmp^=getsum(pos[v]-1);
        tmp^=getsum(pos[u]);
        return tmp;
    }
    void change(int u,int value)
    {
        insert(pos[u],stone[u]);
        insert(pos[u],value);
        stone[u]=value;
    }
    int main()
    {
        freopen("nim.in","r",stdin);
        freopen("nim.out","w",stdout);
        int a,b;
        getnum(n);
        for(int i=1;i<=n;i++)
            getnum(stone[i]);
        for(int i=1;i<n;i++)
            getnum(a),getnum(b),adde(a,b);
        bfs(1);
        getnum(q);
        for(int i=1;i<=q;i++)
        {
            scanf("%s",opt);
            //getnum(a),getnum(b);
            scanf("%d %d",&a,&b);
            
            if(opt[0]=='C')
            {
                change(a,b);
            }
            else if(opt[0]=='Q')
                {
                    printf((query(a,b)!=0)?"Yes
    ":"No
    ");
                }
        }
        return 0;
    }
    

      

    //方法二:先dfs序,倍增求lca,dfs采用了非递归写法。
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #define MAXN 500005
    using namespace std;
    #define lowbit(x) (x&-x)
    int fir[MAXN],edge[MAXN<<1],nxt[MAXN<<1],ecnt,pos,n,q;
    char opt[3];
    int f[MAXN][20];
    int depth[MAXN];
    int que[MAXN],head,tail;
    int btree[MAXN<<1];
    int stone[MAXN];
    int stk1[MAXN],stk2[MAXN],top,st[MAXN],ed[MAXN];
    bool vis[MAXN];
    void getnum(int &t)
    {
        t=0;
    	char c;
    	int flag=1;
    	while(c=getchar(),c<'0'||c>'9')if(c=='-')flag=-1;
    	while(c<='9'&&c>='0'){t=t*10+c-48;c=getchar();}
    	t*=flag;
    }
    void adde(int a,int b)
    {
    	ecnt++;
    	edge[ecnt]=b,nxt[ecnt]=fir[a],fir[a]=ecnt;
    	ecnt++;
    	edge[ecnt]=a,nxt[ecnt]=fir[b],fir[b]=ecnt;
    }
    void dfs(int s)
    {
    	stk1[++top]=s;
    	stk2[top]=fir[s];
    	st[s]=++pos;
    	depth[s]=1;
    	vis[s]=1;
    	for(int i=0;i<19;i++)
    	f[s][i]=0;
    	while(top)
    	{
    			int i=stk2[top];
    			if(i)
    			{int v=edge[i];
    			stk2[top]=nxt[i];
    			if(!vis[v])
    			{
    				vis[v]=1;
    				depth[v]=depth[stk1[top]]+1;
    				f[v][0]=stk1[top];
    				for(int i=1;i<19;i++)
    				f[v][i]=f[f[v][i-1]][i-1];
    
    				stk1[++top]=v;
    				st[v]=++pos;
    				stk2[top]=fir[v];
    			}
    			}
    			else
    				ed[stk1[top--]]=++pos;
    	}
    }
    void update(int x,int value)
    {
    	while(x<=2*n)
    	{
    		btree[x]^=value;
    		x+=lowbit(x);
    	}
    }
    int getsum(int x)
    {
    	int sum=0;
    	while(x>0)
    	{
    		sum^=btree[x];
    		x-=lowbit(x);
    	}
    	return sum;
    }
    
    int getlca(int a,int b)
    {
    	if(depth[a]<depth[b])swap(a,b);
    	int diff=depth[a]-depth[b];
    	for(int i=0;i<20;i++)
    	{
    		if((diff>>i)&1)
    		a=f[a][i];
    	}
    	if(a==b)return a;
    	for(int i=19;i>=0;i--)
    	{
    		if(f[a][i]!=f[b][i])
    		a=f[a][i],b=f[b][i];
    	}
    	return f[a][0];
    }
    void change(int pos,int value)
    {
    	update(st[pos],stone[pos]);
    	update(ed[pos],stone[pos]);
    	update(st[pos],value);
    	update(ed[pos],value);
    	stone[pos]=value;
    }
    int query(int a,int b)
    {
        int sum=0;
    	int c=getlca(a,b);
    	sum=getsum(st[a]);
    	sum^=getsum(st[b]);
    	sum^=stone[c];
    	return sum;
    }
     int main()
     {
     	int a,b;
     	getnum(n);
     	for(int i=1;i<=n;i++)
     		getnum(stone[i]);
     	for(int i=1;i<n;i++)
     		getnum(a),getnum(b),adde(a,b);
        dfs(1);
        for(int i=1;i<=n;i++)
     	{
    		update(st[i],stone[i]);
    		update(ed[i],stone[i]);
    	 }
    	getnum(q);
    	for(int i=1;i<=q;i++)
    	{
    		scanf("%s",opt);
    		getnum(a),getnum(b);
    		if(opt[0]=='C')
    			change(a,b);
    		else {
    		    printf(query(a,b)?"Yes
    ":"No
    ");
    		}
    	}
    	return 0;
     }
    

      

  • 相关阅读:
    4 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之Lvs为Mysql-slave做负载均衡
    3 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之heartbeat的搭建
    2 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之MySql的搭建
    1 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之DRBD的搭建
    Python
    Python
    Tools
    DevOps
    Tools
    Tools
  • 原文地址:https://www.cnblogs.com/hefenghhhh/p/9737567.html
Copyright © 2020-2023  润新知