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. CSDN刷阅读数

    今天我们来盘一下csdn,做一个小程序,为什么做这个呢?今天小编看着我的博客的阅读数,唉,惨不忍睹,没办法,只能想一些........呃呃呃呃,你懂的. 话不多说,分析一波csdn的阅读数,计数原理是 ...

  2. angular http interceptors 拦截器使用分享

    拦截器 在开始创建拦截器之前,一定要了解 $q和延期承诺api 出于全局错误处理,身份验证或请求的任何同步或异步预处理或响应的后处理目的,希望能够在将请求移交给服务器之前拦截请求,并在将请求移交给服务 ...

  3. Vue.js的路由之——vue-router快速入门

    直接先上效果图 这个单页面应用有两个路径:/home和/about,与这两个路径对应的是两个组件Home和About. 整个实现过程 JavaScript 创建组件:创建单页面应用需要渲染的组件 创建 ...

  4. Oracle 11g 体系结构概述

    一.Oracle 体系结构主要用来分析数据库的组成.工作过程与原理,以及数据在数据库中的组织与管理机制. Oracle 数据库是一个逻辑概念,而不是物理概念上安装了 Oracle 数据库管理系统的服务 ...

  5. k8s维护常用命令

    k8s维护 1. 不可调度 kubectl cordon k8s-node-1 kubectl uncordon k8s-node-1 #取消 2.驱逐已经运行的业务容器 kubectl drain ...

  6. Jenkins详细教程

    大纲 1.背景 在实际开发中,我们经常要一边开发一边测试,当然这里说的测试并不是程序员对自己代码的单元测试,而是同组程序员将代码提交后,由测试人员测试: 或者前后端分离后,经常会修改接口,然后重新部署 ...

  7. 巧用浏览器F12调试器定位系统前后端bug-转载

    做测试的小伙伴可能用过httpwatch,firebug,fiddler,charles等抓包(数据包)工具,但实际上除了这些还有一个简单实用并的抓包工具,那就是浏览器的F12调试器. httpwat ...

  8. echarts 曲线平滑配置

    来源:https://blog.csdn.net/sinat_36422236/article/details/62430114 series : [ { name:'your name', symb ...

  9. 【python】udp 数据的发送和接收

    import socket def send_message(): # 创建一个udp套接字 udp_socker = socket.socket(socket.AF_INET,socket.SOCK ...

  10. day 04 预科

    目录 变量 什么是变量 变量的组成 变量名的命名规范 注释 单行注释 多行注释 turtle库的使用 今日内容 数据类型基础 变量 具体的值 存不是目的,取才是目的 为了描述世界万物的状态,因此有了数 ...