西安邀请赛-E(树链剖分+线段树)
题目链接:https://nanti.jisuanke.com/t/39272
题意:给一棵树,n个结点,树根为1,n-1条边,每个结点有一个权值。进行3种操作:
1 s t:把1和s之间的最短路径上的所有结点|t。
2 s t:把1和s之间的最短路径上的所有结点&t。
3 s t:把1和s之间的最短路径上的所有结点进行异或,若结果等于t则输出NO,否则输出YES。(不理解的话可以看一下nim博弈论)
思路:很明显的一道题树链剖分题,难的是怎么维护线段树。我们拆成二进制来看,用num[32]维护区间内所有点对应位的1的数量,对于或操作来说,若对应位为1,则区间所有点对应位全改为1,若为0,则不操作; 对于与操作来说,若对应位为0,则区间所有点对应位全为0,若为1,则不操作。而且这两种操作是具有覆盖效果的,那么我们可以用懒惰标记add[i]=1表示该区间第i位全为1,add[i]=-1表示该区间第i位全为0。查询操作时,将查询区间上所有位1的数量模2,即区间异或和的对应位,将其与输入的t比较是否相等即可。
AC代码:
#include<cstdio>
#include<algorithm>
using namespace std; const int maxn=; int cnt1,head[maxn];
int dep[maxn],siz[maxn],fa[maxn],son[maxn],top[maxn],cnt2,id[maxn],w[maxn],wt[maxn],res;
int n,m; struct node1{
int v,nex;
}edge[maxn<<]; void adde(int u,int v){
edge[++cnt1].v=v;
edge[cnt1].nex=head[u];
head[u]=cnt1;
} struct node2{
int l,r,len;
int num[],add[];
}tr[maxn<<]; void pushup(int v){
for(int i=;i<;++i)
tr[v].num[i]=tr[v<<].num[i]+tr[v<<|].num[i];
} void pushdown(int v){
for(int i=;i<;++i){
if(tr[v].add[i]==){
tr[v<<].num[i]=tr[v<<].len;
tr[v<<].add[i]=;
tr[v<<|].num[i]=tr[v<<|].len;
tr[v<<|].add[i]=;
tr[v].add[i]=;
}
if(tr[v].add[i]==-){
tr[v<<].num[i]=;
tr[v<<].add[i]=-;
tr[v<<|].num[i]=;
tr[v<<|].add[i]=-;
tr[v].add[i]=;
}
}
} void build(int v,int l,int r){
tr[v].l=l,tr[v].r=r,tr[v].len=r-l+;
if(l==r){
for(int i=;i<;++i)
if((<<i)&wt[r])
tr[v].num[i]=;
return;
}
int mid=(l+r)>>;
build(v<<,l,mid);
build(v<<|,mid+,r);
pushup(v);
} void update(int v,int l,int r,int op,int k){
if(l<=tr[v].l&&r>=tr[v].r){
if(op==){
for(int i=;i<;++i)
if((<<i)&k){
tr[v].num[i]=tr[v].len;
tr[v].add[i]=;
}
}
else{
for(int i=;i<;++i)
if(!((<<i)&k)){
tr[v].num[i]=;
tr[v].add[i]=-;
}
}
return;
}
pushdown(v);
int mid=(tr[v].l+tr[v].r)>>;
if(l<=mid) update(v<<,l,r,op,k);
if(r>mid) update(v<<|,l,r,op,k);
pushup(v);
} void query(int v,int l,int r){
if(l<=tr[v].l&&r>=tr[v].r){
for(int i=;i<;++i){
if(tr[v].num[i]&)
res^=(<<i);
}
return;
}
pushdown(v);
int mid=(tr[v].l+tr[v].r)>>;
if(l<=mid) query(v<<,l,r);
if(r>mid) query(v<<|,l,r);
} void dfs1(int x,int f,int deep){
fa[x]=f;
dep[x]=deep;
siz[x]=;
int maxson=-;
for(int i=head[x];i;i=edge[i].nex){
int y=edge[i].v;
if(y==f) continue;
dfs1(y,x,deep+);
siz[x]+=siz[y];
if(siz[y]>maxson) son[x]=y,maxson=siz[y];
}
} void dfs2(int x,int tp){
id[x]=++cnt2;
wt[cnt2]=w[x];
top[x]=tp;
if(!son[x]) return;
dfs2(son[x],tp);
for(int i=head[x];i;i=edge[i].nex){
int y=edge[i].v;
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
} void updRange(int x,int y,int op,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(,id[top[x]],id[x],op,k);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(,id[x],id[y],op,k);
} void qRange(int x,int y){
res=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
query(,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
query(,id[x],id[y]);
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
scanf("%d",&w[i]);
for(int i=;i<n;++i){
int x,y;
scanf("%d%d",&x,&y);
adde(x,y);
adde(y,x);
}
dfs1(,,);
dfs2(,);
build(,,n);
while(m--){
int op,s,t;
scanf("%d%d%d",&op,&s,&t);
if(op==||op==)
updRange(,s,op,t);
else{
qRange(,s);
if(res==t) printf("NO\n");
else printf("YES\n");
}
}
return ;
}
西安邀请赛-E(树链剖分+线段树)的更多相关文章
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
随机推荐
- noi.ac #534 猫
题目链接:戳我 [问题描述] 有n座山,m只猫和p个工作人员.山从左往右编号为1∼n,山i和i−1之间的距离是di米. 有一天,猫都到山上去玩了:第i只猫会到山hi去,并一直玩到时间ti,之后就在那座 ...
- CentOS7 升级Openssl的办法
1.查看安装的版本 openssl version -a OpenSSL 1.0.2 2.下载 openssl-1.1.1.tar.gz,目前最新是1.1.1,可以通过修改版本号的方式下载最新版本 最 ...
- LVS集群之NAT模式
集群的分类: (1)HA:高可用集群,有叫双机热备 原理:两台机器A.B,正常是A提供服务,当A机宕机或者服务有问题时,会切换到B机继续提供服务常用的高了永软件:heartbeat和keepalive ...
- HAOI2010软件安装
首先tarjan缩点应该能看出来,然后我用topsort跑了个DAG上的一维dp,结果WA的很惨. 其实用DAG应该也能做,但是DAG强调整体顺序,而对一些局部问题,例如两个儿子怎么分配,是否给当前节 ...
- 从输入url到页面加载完成都发生了什么
https://zhuanlan.zhihu.com/p/23155051 参考 一个http请求的过程 简要介绍一下一个http请求的网络传输过程: DNS Lookup先获得URL对应的IP地址( ...
- Java-内存模型 final 和 volatile 的内存语义
前提:内存屏障 内存屏障(Memory Barrier)与内存栅栏(Memory Fence)是同一个概念. 用于阻止指令重排序.保证了特定操作的执行顺序和某些变量的内存可见性. JMM 内存屏障分为 ...
- PLSQL报错: ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务
一开始吓尿了,以为自己动着什么东西了把数据库玩坏了,谁知道打开服务发现服务没启动........... 我们要确保数据库服务是启动状态
- python - paramiko模块 修改logging提示为静默
import paramiko import logging log = paramiko.util.get_logger("paramiko") log.setLevel(log ...
- mysql sql常用语句
1.说明:创建数据库 CREATE DATABASE database-name 2.说明:删除数据库 drop database dbname 3.说明:备份sql server --- 创建 备份 ...
- 详解nohup和& 区别
nohup 一.[解释] 不挂断地运行命令.no hangup的缩写,意即“不挂断”.一般理解&记住一个命令最简单的方法是记住它是什么缩写,就自然理解了这个命令.nohup运行由 Comman ...