西安邀请赛-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 ...
随机推荐
- SQL Server、SSMS的单独安装
喜欢尝新版本的,可以单独安装数据库.界面管理软件. 不喜欢折腾的可以只安装SQL Server(全选安装,自带界面管理工具) 1.SQL Server,下载地址https://www.microsof ...
- NTT 练习
一 . Rikka with Subset 题目: http://acm.hdu.edu.cn/showproblem.php?pid=5829 参考 https://blog.csdn.net/ ...
- Loooooooooooooooong time no see!
好久没来啦~去年这会一口气写了好多,是因为即将离职,在公司闲的没事,再加上也积累了一些东西想分享. 最近有个朋友给我私信求助,才又想起这里.这快一年时间,又学习了不少东西.从何写起呢,哈哈,不知道啊~ ...
- Java多线程深入理解
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口. 对于直接继承Thread的类来说,代码大致框架是: ? 1 2 3 4 5 6 7 8 9 10 ...
- pl/sql 过程 函数(写一个过程,输入部门编号,在控制台打印这个部门的名称,总人数,平均工资(基本工资+奖金))
1.编写过程,输入三角形三个表的长度.在控制台打印三角形的面积. create or replace procedure pro_s(v_a number,v_b number,v_c number) ...
- 新版uni-app 在微信小工具调试遇到报错解决方案
问题描述:我在运行到微信小程序是运行报错打不开微信小程序报错如下图 结局方案:将微信小程序安全设置开启如下图
- invalid new-expression of abstract class type 'CurveFittingEdge'
目录 一 报错原因 注:原创不易,转载请务必注明原作者和出处,感谢支持! 一 报错原因 今天遇到了一个之前从未遇到的报错: error: invalid new-expression of abstr ...
- Orcal设置默认插入数据的日期和时间
CREATE TABLE TEST_DATE_TIME( id integer, operdate )default "TO_CHAR"(SYSDATE,'yyyy-MM-dd') ...
- android下载网络图片,设置宽高,等比缩放
使用Picasso组件去下载图片会发现图片宽高会变形不受等比缩放控制,即使设置了图片的 scaleType,可能是对Picasso的api没有用对, Picasso.with(this.activit ...
- Numpy中matrix()和array()的区别
matrix() 和 array() 的区别,主要从以下方面说起: 1. 矩阵生成方式不同 import numpy as np a1 = np.array([[1, 2], [3, 4]]) b1 ...