西安邀请赛-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 ...
随机推荐
- [Android]第一个cm调试分析
0x00:写在前面 一直想入门Android安全,当时是极客大挑战出题的时候,被cx表哥甩锅强行去学了点android的开发,之后慢慢接触,感觉还是挺有意思的.cx表哥说先从逆向分析入门吧,之后可以 ...
- cookbook 11.1 在文本控制台中显示进度条
任务: 在进行长时间操作时,向用户显示一个"进度指示条". 解决方案: #coding=utf-8 import sys class progressbar(object): de ...
- Confluence 6.15 修改历史(Change-History)宏
修改历史(Change-History)宏显示了页面一个的更新历史:版本号,作者,日期和备注.这些内容将会在同一栏中进行显示. 屏幕截图:Confluence 中的修改历史(Change-Histor ...
- B. Interesting Array(线段树)
B. Interesting Array time limit per test 1 second memory limit per test 256 megabytes input standard ...
- linux安装vlc视频播放器
文章来自转发 最近,打算在centos7.2上安装一个叫MPlayer的视频播放器,但是折腾好久,得到的结果只是可以播放,但是却没有声音.无奈之下另寻他路.最后选择安装VLC视频播放器. 我的linu ...
- 如何安装Vscode软件及设置成中文界面?
最新小编开始研究前端,想写点东东玩,要想开始首先就要安装工具,写前端有好几个工具,安装推荐开源的vscode,第一次安装是英文版的,如何修改成中文版,也是很简单的,跟随小编一起来安装设置工具吧. 方法 ...
- 石川es6课程---6、解构赋值
石川es6课程---6.解构赋值 一.总结 一句话总结: 结构相同一一对应的方式赋值:let [json, arr, num, str] = [{ a: 1, b: 2 }, [1, 2, 3], 8 ...
- vsftpd 配置上传失败553
1查看ftp服务 ftp://ftpuser:123456@10.11.102.58:8023 2 getsebool -a | grep ftp 临时关闭 [root@xuegod63~]# get ...
- pandas之to_datetime时区转换
from datetime import date, datetime, timedelta import time import pandas as pd from pand ...
- python 面对对象 类(继承, 多态)
继承,继承其它实例化样本的属性和方法,需要在声明里重新定义和使用 class School(object): def __init__(self, name, addr): self.name = n ...