Tree

Ming and Hong are playing a simple game called nim game. They have nn piles of stones numbered 11 to nn ,the ii-th pile of stones has a_iai​ stones. There are n - 1n−1 bidirectional roads in total. For any two piles, there is a unique path from one to another. Then they take turns to pick stones, and each time the current player can take arbitrary number of stones from any pile. Of course, the current player should pick at least one stone. Ming always takes the lead. The one who takes the last stone wins this game. Ming and Hong are smart enough so they will make optimal operations every time.

m events will take place. Each event has a type called optopt ( the value of opt is among \{1,2,3 \}{1,2,3} ).

If optopt is 11, modify the numbers of stones of piles on the path from 1 to ss by the following way: change a_iai​ to a_i|tai​∣t. ( s,ts,t will be given).

If optopt is 22 , modify the numbers of stones of piles on the path from 1 to ss by the following way: change a_iai​ to a_i\&tai​&t. (s,ts,t will be given).

If optopt is 33 , they play nim game. Firstly, take the piles on the path from 1 to SS into consideration. At the same time create a new pile with t stones and take it into consideration. Now they have taken + 1+1 piles into consideration. Then they play nim game on these S + 1S+1 piles. You need to figure out if Ming is going to win the game. Amazingly, after playing nim game, the numbers of stones of each pile on the path from 11 to ss will return to the original numbers.

Input

Each test file contains a single test case. In each test file:

The first line contains two integers,nn and mm.

The next line contains⁡ nn integers, a_iai​.

The next n - 1 lines, each line contains two integers, b, c, means there is a bidirectional road between pile b and pile c.

Each of the following mm lines contains 33 integers, optopt, ss and ⁡tt.

If optopt is 11, change all the stone numbers of piles on the path from 11 to ss in the first way (a_i(ai​ to a_i|t)ai​∣t)

If optopt is 22, change all the stone numbers of piles on the path from 11 to ss in the second way (a_i(ai​ to a_i\&t)ai​&t).

If optopt is 33, we query whether Ming will win when given ss and tt ⁡as parameters in this round.

It is guaranteed:1 \le n,m \le 10^51≤n,m≤105,

0 \le a_i \le 10^90≤ai​≤109,

1 \le opt \le 3, 1 \le s \le 10^5, 0 \le t \le 10^9.1≤opt≤3,1≤s≤105,0≤t≤109.

Output

If optopt is 33, print a line contains one word “YES” or “NO” (without quotes) , representing whether Ming will win the game.

样例输入复制

6 6
0 1 0 3 2 3
2 1
3 2
4 1
5 3
6 3
1 3 0
2 3 1
1 1 0
3 5 0
2 4 1
3 3 1

样例输出复制

YES
NO

题意就是给你一棵点权树,有三种操作:

1.从根节点到节点u的路径上的所有点的权值&t

2.从根节点到节点u的路径上的所有点的权值|t

3.查询根节点到节点u的路径所有点的异或和是否等于t

3操作是和尼姆博奕联系起来的,分析得出以上操作。

思路:树链剖分给点重新编号然后线段树来维护。因为涉及到位运算,对于每一位建一棵线段树,建最多不超过31棵线段树。

然后每一棵线段树维护当前位上的区间异或和,当前二进制位为1的数量。若区间和为奇数说明这一位的区间异或结果为1,否则为0。

对于修改操作:

  • 修改1为区间或操作:对于二进制的第i位,若t的二进制第i位为1,则会将从1到s的路径上的点权的二进制第i位全变为1,若t的二进制第ii位为0,则无影响

  • 修改2为区间与操作:对于二进制的第ii位,若t的二进制第ii位为0,则会将从1到s的路径上的点权的二进制第i位全变为0,若t的二进制第ii位为1,则无影响

参考来源:

2019 ACM-ICPC 西安全国邀请赛 E-Tree 树链剖分+线段树

2019 icpc西安邀请赛 E. Tree(树链剖分+带修改的区间异或和)

我写的时候,直接按以前的板子写发现过不了,后来看的人家的题解改的过的。不知道为什么。

代码:

 //E.树链剖分+线段树
//Nim和!= 0时,先手胜利,否则失败
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll; const double PI=acos(-1.0);
const double eps=1e-;
//const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e5+;
const int maxm=+;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 int tree[][maxn<<],lazy[][maxn<<];
int n,m,r,mod;
int head[maxn],tot; int son[maxn],tid[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
int w[maxn],wt[maxn]; struct Edge{
int to,next;
}edge[maxn<<]; void add(int u,int v)//链式前向星存边
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
} void init()//初始化
{
memset(head,-,sizeof(head));
tot=;cnt=;
} //线段树部分
void pushup(int tree[],int lazy[],int rt)//上传lazy标记
{
tree[rt]=tree[rt<<]+tree[rt<<|];
if(lazy[rt<<]==lazy[rt<<|]) lazy[rt]=lazy[rt<<];
} void pushdown(int tree[],int lazy[],int rt,int m)//下放lazy标记
{
if(lazy[rt]==-){
return ;
} lazy[rt<<]=lazy[rt];
lazy[rt<<|]=lazy[rt];
tree[rt<<]=(m-(m>>))*lazy[rt];
tree[rt<<|]=(m>>)*lazy[rt];
lazy[rt]=-;
} void update(int tree[],int lazy[],int L,int R,int c,int l,int r,int rt)//区间更新
{
if(L<=l&&r<=R){
lazy[rt]=c;
tree[rt]=c*(r-l+);
return ;
} pushdown(tree,lazy,rt,r-l+);
int m=(l+r)>>;
if(L<=m) update(tree,lazy,L,R,c,lson);
if(R> m) update(tree,lazy,L,R,c,rson);
pushup(tree,lazy,rt);
} int query(int tree[],int lazy[],int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){
return tree[rt];
} int ret=;
pushdown(tree,lazy,rt,r-l+);
int m=(l+r)>>;
if(L<=m) ret+=query(tree,lazy,L,R,lson);
if(R> m) ret+=query(tree,lazy,L,R,rson);
return ret;
} //树链剖分部分
void dfs1(int u,int father)
{
siz[u]=;//记录每个节点子树大小
fa[u]=father;//标记节点的父亲
dep[u]=dep[father]+;//标记深度
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==father) continue;//如果连接的是当前节点的父亲节点,则不处理
dfs1(v,u);
siz[u]+=siz[v];//直接子树节点相加,当前节点的size加上子节点的size
if(siz[v]>siz[son[u]]){//如果没有设置过重节点son或者子节点v的size大于之前记录的重节点son,进行更新,保存重儿子
son[u]=v;//标记u的重儿子为v
}
}
} void dfs2(int u,int tp)
{
top[u]=tp;//标记每个重链的顶端
tid[u]=++cnt;//每个节点剖分以后的新编号(dfs的执行顺序)
wt[cnt]=w[u];//新编号的对应权值
if(!son[u]) return ;//如果当前节点没有处在重链上,则不处理,否则就将这条重链上的所有节点都设置成起始的重节点
dfs2(son[u],tp);//搜索下一个重儿子
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==fa[u]||v==son[u]) continue;//处理轻儿子,如果连接节点不是当前节点的重节点并且也不是u的父节点,则将其的top设置成自己,进一步递归
dfs2(v,v);//每一个轻儿子都有一个从自己开始的链
}
} void update_huo(int s,int t)
{
// int x=1,y=s;
for(int i=;i<;i++){
if(t&(<<i)){
int v=s;
while(v){
int father=top[v];
int l=tid[father],r=tid[v];
update(tree[i],lazy[i],l,r,,,n,);
v=fa[father];
} // while(top[x]!=top[y]){
// if(dep[top[x]]<dep[top[y]]) swap(x,y);//使x深度较大
// update(tree[i],lazy[i],tid[top[x]],tid[x],1,1,n,1);
// x=fa[top[x]];
// }
//
// if(dep[x]>dep[y]) swap(x,y);//使x深度较小
// update(tree[i],lazy[i],tid[x],tid[y],1,1,n,1);
}
}
} void update_yihuo(int s,int t)
{
// int x=1,y=s;
for(int i=;i<;i++){
if(t&(<<i)) continue;
int v=s;
while(v){
int father=top[v];
int l=tid[father],r=tid[v];
update(tree[i],lazy[i],l,r,,,n,);
v=fa[father];
}
// while(top[x]!=top[y]){
// if(dep[top[x]]<dep[top[y]]) swap(x,y);//使x深度较大
// update(tree[i],lazy[i],tid[top[x]],tid[x],0,1,n,1);
// x=fa[top[x]];
// }
//
// if(dep[x]>dep[y]) swap(x,y);//使x深度较小
// update(tree[i],lazy[i],tid[x],tid[y],0,1,n,1);
}
} //bool play_nim(int s,int t)
//{
// int x=1,y=s;
// int flag=0;
// for(int i=0;i<31;i++){
// int ans=0;
// while(top[x]!=top[y]){
// if(dep[top[x]]<dep[top[y]]) swap(x,y);//使x深度较大
// ans+=query(tree[i],lazy[i],tid[top[x]],tid[x],1,n,1);
// x=fa[top[x]];
// }
//
// if(dep[x]>dep[y]) swap(x,y);//使x深度较小
// ans+=query(tree[i],lazy[i],tid[x],tid[y],1,n,1);
// ans=ans&1;
// if((t&(1<<i)&&ans)||(!(t&(1<<i)&&!ans))){
// flag=1;break;
// }
// }
// if(flag) return true;
// else return false;
//} bool play_nim(int k,int s,int t)
{
// int x=1,y=s;
int ans=;
while(s){
int father=top[s];
int l=tid[father],r=tid[s];
ans+=query(tree[k],lazy[k],l,r,,n,);
s=fa[father];
}
// while(top[x]!=top[y]){
// if(dep[top[x]]<dep[top[y]]) swap(x,y);//使x深度较大
// ans+=query(tree[k],lazy[k],tid[top[x]],tid[x],1,n,1);
// x=fa[top[x]];
// }
//
// if(dep[x]>dep[y]) swap(x,y);//使x深度较小
// ans+=query(tree[k],lazy[k],tid[x],tid[y],1,n,1); ans=ans&;
if((t&(<<k))&&ans) return true;
if(!(t&(<<k))&&!ans) return true;
return false;
} int main()
{
scanf("%d%d",&n,&m);
init();
for(int i=;i<=n;i++)
scanf("%d",&w[i]);//点权
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1(,);//根节点
dfs2(,);
for(int i=;i<=n;i++){//建树,每一位建一棵线段数
for(int k=;k<;k++){
if(w[i]&(<<k)) update(tree[k],lazy[k],tid[i],tid[i],,,n,);
}
}
while(m--){
int op,s,t;
scanf("%d%d%d",&op,&s,&t);
if(op==){
update_huo(s,t);
}
else if(op==){
update_yihuo(s,t);
}
// else if(op==3){
// bool ans=play_nim(s,t);
// if(ans) printf("YES\n");
// else printf("NO\n");
// } else if(op==){
int flag=;
for(int i=;i<;i++){
if(!play_nim(i,s,t)){
flag=;break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
}
}
return ;
}
 

计蒜客 39272.Tree-树链剖分(点权)+带修改区间异或和 (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest E.) 2019ICPC西安邀请赛现场赛重现赛的更多相关文章

  1. 计蒜客 39280.Travel-二分+最短路dijkstra-二分过程中保存结果,因为二分完最后的不一定是结果 (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest M.) 2019ICPC西安邀请赛现场赛重现赛

    Travel There are nn planets in the MOT galaxy, and each planet has a unique number from 1 \sim n1∼n. ...

  2. 计蒜客 39279.Swap-打表找规律 (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest L.) 2019ICPC西安邀请赛现场赛重现赛

    Swap There is a sequence of numbers of length nn, and each number in the sequence is different. Ther ...

  3. 计蒜客 39270.Angel's Journey-简单的计算几何 ((The 2019 ACM-ICPC China Shannxi Provincial Programming Contest C.) 2019ICPC西安邀请赛现场赛重现赛

    Angel's Journey “Miyane!” This day Hana asks Miyako for help again. Hana plays the part of angel on ...

  4. 计蒜客 39268.Tasks-签到 (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest A.) 2019ICPC西安邀请赛现场赛重现赛

    Tasks It's too late now, but you still have too much work to do. There are nn tasks on your list. Th ...

  5. POJ3237 Tree 树链剖分 边权

    POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...

  6. POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 12247   Accepted: 3151 Descriptio ...

  7. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

  8. Hdu 5274 Dylans loves tree (树链剖分模板)

    Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...

  9. BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时 ...

随机推荐

  1. 所有子模块都要执行的checkstyle检查

    <!-- 所有子模块都要执行的checkstyle检查 --> <plugin> <groupId>org.apache.maven.plugins</gro ...

  2. mqtt client api: 阻塞API

    fusesource版本:mqtt-client-1.11.jar下载地址:https://github.com/fusesource/mqtt-client fusesource提供三种mqtt c ...

  3. CephFS 使用

    原文:https://www.jianshu.com/p/c22ff79c4452 之前介绍了 RBD 的使用方法,有了 RBD,远程磁盘挂载的问题就解决了,但 RBD 的问题是不能多个主机共享一个磁 ...

  4. Github下载慢和下载过程中断等情况的解决方案

    Github下载慢和下载过程中断等情况的解决方案   最近老大push项目,正常的git clone每次都是下载一部分就断掉了. 尝试了修改hosts文件的方式,更换了延迟最低的域名也没啥用(难道我姿 ...

  5. 【RAC】 RAC For W2K8R2 安装--操作系统环境配置 (二)

    [RAC] RAC For W2K8R2 安装--操作系统环境配置 (二) 一.1  BLOG文档结构图 一.2  前言部分 一.2.1  导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可 ...

  6. 【Python】模块和包

    模块 模块的概念 1. 每一个以扩展名 `py` 结尾的 `Python` 源代码文件都是一个 模块 2. 模块名 同样也是一个 标识符,需要符合标识符的命名规则 3. 在模块中定义的 全局变量 .函 ...

  7. Linux环境变量设置declare/typeset

    形而上,质在内!形形色色,追寻本质! declare/typeset declare 或 typeset 是一样的功能,就是在宣告变数的属性 declare 后面并没有接任何参数,那么bash 就会主 ...

  8. cadvisor应用

    cadvisor主页:https://github.com/google/cadvisor 容器主页:https://hub.docker.com/r/google/cadvisor cAdvisor ...

  9. C语言中指针是什么?

    学习交流可加 微信读者交流①群 (添加微信:coderAllen) 程序员技术QQ交流①群:736386324 --- ==恶名昭著的指针究竟是什么== " 指针是一种保存变量地址的变量,在 ...

  10. js面向对象--由浅入深

    基本概念 ECMA关于对象的定义是:”无序属性的集合,其属性可以包含基本值.对象或者函数.“对象的每个属性或方法都有一个名字,而每个名字都映射到一个值. 类 在现实生活中,相似的对象之间往往都有一些共 ...