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. Java中Date、String、Calendar类型之间的转化

    1.Calendar 转化 String   //获取当前时间的具体情况,如年,月,日,week,date,分,秒等   Calendar calendat = Calendar.getInstanc ...

  2. 对比分析HashMap、LinkedHashMap、TreeMap

    HashMap的原理 :简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象.HashMap 底层采用一个 Entry[] 数组来保存所有的 ...

  3. requirejs:模块加载(require)及定义(define)时的路径理解

    给新来的实习生普及下JS基本知识,看到比较好的文章 转载https://blog.csdn.net/xuxiaoping1989/article/details/52384778 接触过require ...

  4. 解决centos7下 selenium报错--unknown error: DevToolsActivePort file doesn't exist

    解决centos7下 selenium报错--unknown error: DevToolsActivePort file doesn't exist 早上在linux下用selenium启动Chro ...

  5. 使用IDEA运行项目时提示:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除

    如图 在使用IDEA运行项目时,在下方提示:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除 这是因为JDK版本问题 解决方法如下:左上角 file ——> Projec ...

  6. Deployment

    Deployment RC是kubernetes中的一个核心概念,Deployment 是新一代的RC,除了拥有RC的功能外,还具备一下特性: 支持事件和状态查看:可以查看Deployment升级的状 ...

  7. Linux操作系统启动故障排错之"/etc/fstab"文件被删除恢复案例

    Linux操作系统启动故障排错之"/etc/fstab"文件被删除恢复案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.模拟故障 [root@yinzhe ...

  8. Linux标准IO和管道

    Linux标准IO和管道 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.标准输入和输出 程序:指令+数据 读入数据:Input 输出数据:Output 打开的文件都有一个fd: ...

  9. 阿里云云计算助理工程师认证(ACA)

    经过两天的学习(观看视频,阅读官方帮助文档),完成了初级云计算认证. 本次考试难度相对较低,考察内容较为初级 考点主要考察学员是否真正的动手实验过,不局限于视频中讲解的内容,较多的考点为视频中操作演示 ...

  10. Codeforces Round #574 (Div. 2)题解

    比赛链接 传送门 A题 题意 \(n\)个人每个人都有自己喜欢喝的\(vechorka\)口味,现在给你\(\lceil n/2\rceil\)箱\(vechorka\),每箱有两瓶,问最多能有多少个 ...