【块状树】【博弈论】bzoj3729 Gty的游戏

块状树,每个块的根记录一下当前块内距块根为奇数距离的异或和和偶数距离的异或和,询问的时候讨论一下即可。

总的节点数可能超过50000。

#include<cstdio>
#include<cmath>
using namespace std;
#define N 100001
int n,m,L,a[N];
int en,v[N<<1],next[N<<1],first[N];
int e2,v2[N<<1],nex2[N<<1],firs2[N];
int sz,top[N],siz[N],fa[N],xorv[2][N],meiz,dep[N];
void AddEdge(int U,int V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
void AddEdg2(int U,int V)
{
	v2[++e2]=V;
	nex2[e2]=firs2[U];
	firs2[U]=e2;
}
void makeblock(int U)
{
	for(int i=first[U];i;i=next[i])
	  if(v[i]!=fa[U])
	    {
	      fa[v[i]]=U;
	      dep[v[i]]=dep[U]+1;
	      if(siz[top[U]]<sz)
	        {
	          ++siz[top[U]];
	          top[v[i]]=top[U];
	        }
	      makeblock(v[i]);
	    }
}
void makeGoto(int U)
{
    for(int i=first[U];i;i=next[i])
      if(v[i]!=fa[U])
        {
          if(top[v[i]]!=top[U])
            AddEdg2(top[U],v[i]);
          makeGoto(v[i]);
        }
}
void dfs_init(int U,bool d)
{
	xorv[d][top[U]]^=a[U];
	for(int i=first[U];i;i=next[i])
	  if(v[i]!=fa[U]&&top[v[i]]==top[U])
	    dfs_init(v[i],d^1);
}
int ans;
void dfs_Goto(int U,bool d)
{
	ans^=xorv[d][top[U]];
	for(int i=firs2[U];i;i=nex2[i])
	  dfs_Goto(v2[i],d^((dep[v2[i]]-dep[U])&1));
}
void dfs_block(int U,bool d)
{
	if(d) ans^=a[U];
	for(int i=first[U];i;i=next[i])
	  if(v[i]!=fa[U])
	    {
	      if(top[v[i]]==top[U])
	        dfs_block(v[i],d^1);
	      else
	        dfs_Goto(v[i],d);
	    }
}
void query(int U)
{
	ans=0;
	if(U==top[U]) dfs_Goto(U,1);
	else dfs_block(U,0);
}
void Update(int U,int x)
{
	xorv[0][top[U]]=xorv[1][top[U]]=0;
	a[U]=x%(L+1);
	dfs_init(top[U],0);
}
void AddNode(int U,int V,int x)
{
	++n;
	fa[V]=U;
	dep[V]=dep[U]+1;
	if(siz[top[U]]<sz)
      {
        top[V]=top[U];
        ++siz[top[V]];
      }
    else
      {
        top[V]=V;
        siz[V]++;
        AddEdg2(top[U],V);
      }
    AddEdge(U,V);
    a[V]=x%(L+1);
    xorv[(dep[V]-dep[top[V]])&1][top[V]]^=a[V];
}
int main()
{
	int x,y,c,op;
	scanf("%d%d",&n,&L);
	for(int i=1;i<=n;++i)
	  {
	  	scanf("%d",&a[i]);
	  	top[i]=i;
	  	siz[i]=1;
	  	a[i]%=(L+1);
	  }
	for(int i=1;i<n;++i)
	  {
	  	scanf("%d%d",&x,&y);
	  	AddEdge(x,y);
	  	AddEdge(y,x);
	  }
	sz=sqrt(n);
	makeblock(1);
	makeGoto(1);
	for(int i=1;i<=n;++i)
	  if(top[i]==i)
	    dfs_init(i,0);
	scanf("%d",&m);
	for(;m;--m)
	  {
	  	scanf("%d%d",&op,&x); x^=meiz;
	  	if(op==1)
	  	  {
	  	  	query(x);
	  	  	if(ans)
	  	  	  {
	  	  	  	++meiz;
	  	  	  	puts("MeiZ");
	  	  	  }
	  	  	else puts("GTY");
	  	  }
	  	else if(op==2)
	  	  {
	  	  	scanf("%d",&c); c^=meiz;
	  	  	Update(x,c);
	  	  }
	  	else
	  	  {
	  	  	scanf("%d%d",&y,&c); y^=meiz; c^=meiz;
	  	  	AddNode(x,y,c);
	  	  }
	  }
	return 0;
}
时间: 2024-10-25 12:19:24

【块状树】【博弈论】bzoj3729 Gty的游戏的相关文章

【块状树】bzoj3731 Gty的超级妹子树

带 加点 删边的块状树. 加点在 bzoj3720 说过. 删边其实就是块顶打标记,记录其属于哪棵树,防止在dfs搜集答案时跑到别的树上. 然后暴力把所在块拆开. 好像用邻接表存图,直接在vector里删边也行? 1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<vector> 5 using namespace std; 6 #define maxn 200001 7

[BZOJ3729]Gty的游戏

试题描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gty很快计算出了策略.但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点.gty不忍心打击妹子,所以他将这个问题交给了你.另外由于gty十分绅士,所以他将先手让给了妹子. 输入 第一行两个数字,n和L,n<=5*10^4,L<=10^9第二行n个数字,表示每个节点初始石子数.接下来n-

【kruscal】【最小生成树】【块状树】bzoj3732 Network

跟去年NOIP某题基本一样. 最小生成树之后,就变成了询问连接两点的路径上的权值最大的边. 倍增LCA.链剖什么的随便搞. 块状树其实也是很简单的,只不过每个点的点权要记录成“连接其与其父节点的边的权值”,然后暴力LCA时不要用LCA的值更新答案了. 1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #

【块状树】【树链剖分】【线段树】bzoj3531 [Sdoi2014]旅行

离线后以宗教为第一关键字,操作时间为第二关键字排序. <法一>块状树,线下ac,线上tle…… #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> using namespace std; queue<int>q; int f,c; inline void R(int &x){ c=0;f=1;

BZOJ 1086 SCOI2005 王室联邦 块状树

题目大意:给定一棵树,要求将这棵树分成一些块,使每块大小在[B,3B]之间 <手把手教你块状树系列> - -终于搞懂这题怎么做了 - -去网上扒了个代码居然是错的 坑死我了 - -还好题解的思想是对的 朴素的分块方式是贪心 能加就加 这种方法存在着严重的效率问题 可以被菊花卡成O(n)块 因此我们可以为其它的块预留位置 如果一块大小刚好>=b 就将这坨东西分成一块 首先任选一点开始深搜 维护一个栈 每个点退出递归时压栈 自下至上进行合并 如果某棵子树深搜完之后栈内元素数>=b 就把

【块状树】【树链剖分】bzoj1036 [ZJOI2008]树的统计Count

很早之前用树链剖分写过,但是代码太长太难写,省选现场就写错了. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 #define lson rt<<1,l,m 6 #define rson rt<<1|1,m+1,r 7 #define maxn 60000 8 int n,m,u,v; 9 int V[maxn],Next[

【最近公共祖先】【块状树】CODEVS 1036 商务旅行

在线块状树LCA模板. 1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 #define N 30001 7 vector<int>G[N]; 8 typedef vector<int>::iterator ITER; 9 int dep[N],x,y,fa[N],top[N],s

【BZOJ3720】Gty的妹子树 块状树

[BZOJ3720]Gty的妹子树 我曾在弦歌之中听过你,檀板声碎,半出折子戏.舞榭歌台被风吹去,岁月深处尚有余音一缕……Gty神(xian)犇(chong)从来不缺妹子……他来到了一棵妹子树下,发现每个妹子有一个美丽度……由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣.他想知道某个子树中美丽度大于k的妹子个数.某个妹子的美丽度可能发生变化……树上可能会出现一只新的妹子……维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi.支持以下操作:0 u x 

BZOJ 3720 Gty的妹子树 块状树

题目大意:维护一棵树,每个点有一个权值,提供下列操作: 1.询问某棵子树中有多少个节点的权值大于x 2.修改某个节点的权值 3.增加一个叶子节点 强制在线 传说中的树分块 首先DFS,对于每个节点,如果这个节点的父亲节点所在块未满,就塞进父节点所在块中,否则自成一块,然后与父节点所在的块连边 添加节点同理 然后就按照分块直接搞吧0.0 细节实在是太多了 所以写挂的地方看看本蒟蒻的代码就好了0.0 #include <cmath> #include <cstdio> #include