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. Outlook 邮件助手

    Outlook 邮件助手 1 Overview 2 C# 编程 3 Outlook 设置 3.1 Outlook 2013 3.2 Outlook 2010 1 Overview 本章将示例如何开发一 ...

  2. Java——简单实现学生管理系统

    import java.io.*;import java.util.ArrayList;import java.util.Scanner;class MyObjectOutputStream exte ...

  3. 安卓自定义View基础 --坐标系,角度弧度,颜色

    转自:https://www.gcssloop.com/customview/CustomViewIndex/ 1.坐标系 2.角度弧度 3.颜色 一.屏幕坐标系和数学坐标系的区别 由于移动设备一般定 ...

  4. 《区块链DAPP开发入门、代码实现、场景应用》笔记3——Ethereum Wallet的安装

    以太坊官方网站可以下载最新版本的Ethereum Wallet,用户无需选择,浏览器会根据访问者操作系统版本自动展现合适的版本,点击DOWNLOAD按钮下载即可安装,如图2.9所示,其下载网址: ht ...

  5. CRC-CCITT CRC-16

    CRC分为以下几种标准: CRC-12码 CRC-16码 CRC-CCITT码 CRC-32码 在线CRC计算器 https://www.lammertbies.nl/comm/info/crc-ca ...

  6. C/C++ 关于数组和指针的总结

    1.数组的声明形如a[d],其中a是数组的名字,d是数组的维度,编译的时候数组的维度应该是已知的,所以维度d必须是一个常量.如果要定义一个不知道元素个数的以为数组,那么请使用vector容器: uns ...

  7. 数据库与数据仓库的区别实际讲的是OLTP与OLAP的区别

    什么是数据仓库 数据仓库,英文名称为Data Warehouse,可简写为DW或DWH.数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合.它出于分析性报告和决策支持目的而创建. ...

  8. jenkins使用邮件功能

    jenkins发送邮件 在日常构建后,需要及时将构建结果发送给相应的人员.这时就可以使用jenkins自带的邮件配置系统. 1 开通邮箱的SMTP服务,需要发送短信验证开启 2 进入"系统管 ...

  9. 【转】Go调度器原理浅析

    goroutine是golang的一大特色,或者可以说是最大的特色吧(据我了解),这篇文章主要翻译自Morsing的[这篇博客](http://morsmachine.dk/go-scheduler) ...

  10. PAT甲级1005水题飘过

    题目分析:用一个字符串输入之后遍历每一位求和后,不断%10获取最后一位存储下来,逆序用对应的英文单词输出(注意输入为0的情况) #include<iostream> #include< ...