虚
题目背景
作为一位ikun,小T决定在生日这一天为坤坤做些什么。
她决定向全村的人民宣传坤坤。她所在的村庄是一个\(n\)个节点的树。并且这棵树以1号点为根。每个节点上有一位村民,他们初始每个人对坤坤可能喜欢(用1表示),也可能讨厌(用0表示)。
接下来她会进行m次操作,第i次操作形如:
"S x" 表示向点x的子树内的每个人安利一次坤坤。这会让本来喜欢坤坤的人变得讨厌坤坤,而本来讨厌坤坤的人变得喜欢
"Q x" 表示询问点x的子树内有多少人喜欢坤坤??????
你能帮帮她么?
输入格式
第一行两个正整数\(n,m\),分别表示树的点数和操作个数。
接下来一行一个长度为\(n\)的01串,第\(i\)位描述编号为\(i\)的村民的初始状态。1表示喜欢,0表示不喜欢。
接下来\(n?1\)行每行两个数\(x_i,y_i\),表示一条边。
接下来\(m\)行,每行描述一个操作,具体格式如题面所述。
输出格式
对于每个询问,输出一行表示答案。
样例1
input
5 5
11100
1 2
2 3
2 4
3 5
Q 5
Q 4
S 4
Q 1
S 4
output
0
0
4
样例2
input
5 5
01111
1 2
1 3
3 4
1 5
S 5
Q 3
S 5
Q 1
S 1
output
2
4
限制与规定
对于\(30\%\)的数据,\(n,q\le10^3\)。
对于\(50\%\)的数据,保证数据随机。
另有\(20\%\)的数据,保证树的形态是一条链。
对于\(100\%\)的数据,\(n,q\le10^5,1≤x_i,y_i\),每个操作中的\(x\le n\)。
时间限制:1s
空间限制:512MB
区间取反和求和,都是线段树能做的事。所以考虑能不能把树转化成线段,然后再用线段树执行操作。
很明显,如果想要这样做的花,需要把每棵子树放在一起,那么dfs序刚好符合要求。
按照dfs序维护线段树即可。
#include
const int N=1e5+5;
int n,m,idx,x,y,in[N],hd[N],tag[N<<2],tr[N<<2],sz[N],a[N];
char c;
struct edge{
int v,nxt;
}e[N<<1];
void add_edge(int x,int y,int z)
{
e[z]=(edge){y,hd[x]};
hd[x]=z;
}
void pushdown(int o,int l,int r)
{
int mid=(l+r)>>1;
tr[o<<1]=(mid-l+1)-tr[o<<1];
tr[o<<1|1]=(r-mid)-tr[o<<1|1];
tag[o<<1]^=1,tag[o<<1|1]^=1;
tag[o]=0;
}
void update(int o,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
{
tr[o]=(r-l+1)-tr[o];
tag[o]^=1;
return;
}
int mid=l+r>>1;
if(tag[o])
pushdown(o,l,r);
if(mid>=x)
update(o<<1,l,mid,x,y);
if(mid>1,ret=0;
if(tag[o])
pushdown(o,l,r);
if(mid>=x)
ret+=query(o<<1,l,mid,x,y);
if(mid