Tokitsukaze and Colorful Tree
题目大意
给一颗树,每个点有颜色、权值。
求
的值。
这个式子就是颜色相同的,并且u不是v的祖先,并且v不是u的祖先的权值异或完的和。
两种操作:
1 x v 把x点的权值变成v
2 x c 把x点的颜色变成c
每次操作完输出上面公式的值。
点数:1e5
颜色:1~n
权值:2的20次方
题解
离线操作,
把修改一个点的权值或颜色,变成删除一个点,增加一个点。
考虑每种颜色对答案的贡献。
为什么每种颜色每种颜色的统计呢?
因为空间不够开n个树状数组的,并且每种颜色是独立的,不会影响另一种颜色的。
所以记录每种颜色的变化,每次增加或删除就好了。
怎么计算增加删除的贡献呢?
我们可以考虑拆开,拆成20位,计算每一位对答案的贡献。
如果当前的这一位是0,那么统计树中满足条件的1的个数s。
答案加上或者减去(1 << k) * s就好。
怎么统计满足条件的1的个数?
不是当前点的儿子,也不是当前点的祖先的1的数量。
先跑一个dfs序
可以用两个树状数组,
第一个:如果这个点是1.
第二个:表示这个点能被多少个祖先1覆盖。
那么个数就是总共1的个数 - 儿子节点的1的个数 - 祖先节点1的个数。
儿子节点的1的个数是dfs序L[x] R[x]之间t1的个数。
祖先节点1的个数就是t2 中这个点被覆盖的次数。
代码:
#include<algorithm>
#include<iostream>
#include <cstdio>
#include <string>
#include <queue>
#include <cstring>
#include <stack>
#include <bitset>
#include <set>
#include <unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef unordered_set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){
freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){
return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){
a %= mod;ll ans = 1;while(b > 0){
if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{
bool operator()(const pii & a, const pii & b){
return a.second > b.second;}};
int lb(int x){
return x & -x;}
//friend bool operator < (Node a,Node b) 重载
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
// const ll mod = 1e9+7;
const int maxn = 5e5+10;
const int M = 1e7;
int t1[2][maxn];
int t2[2][maxn];
int n;
void add1(int x,int num,int f)
{
while(x <= n)
{
t1[f][x] += num;
x += lb(x);
}
}
int query1(int x,int f)
{
int ans = 0;
while(x)
{
ans += t1[f][x];
x -= lb(x);
}
return ans;
}
void add2(int x,int num,int f)
{
while(x <= n)
{
t2[f][x] += num;
x += lb(x);
}
}
int query2(int x,int f)
{
int ans = 0;
while(x)
{
ans += t2[f][x];
x -= lb(x);
}
return ans;
}
int L[maxn];
int R[maxn];
int col[maxn];
int val[maxn];
std::vector<int> vv[maxn];
int pos =0 ;
void dfs(int x,int fa)
{
L[x] = ++pos;
for (int i =0 ; i < vv[x].size(); i ++ )
{
int v = vv[x][i];
if(v == fa)
continue;
dfs(v,x);
}
R[x] = pos;
}
struct Node
{
int id,val,x,f;
Node(int ii,int vv,int xx,int ff):id(ii),val(vv),x(xx),f(ff){
};
};
std::vector<Node> node[maxn];
ll ans[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
pos = 0;
scanf("%d",&n);
for (int i = 1; i <= n; i ++ )
{
vv[i].clear();
node[i].clear();
}
for (int i = 1; i <= n; i ++ )
scanf("%d",&col[i]);
for (int i = 1; i <= n; i ++ )
{
scanf("%d",&val[i]);
node[col[i]].pb(Node(0,val[i],i,1));
}
for (int i = 1; i < n; i ++ )
{
int x,y;
scanf("%d%d",&x,&y);
vv[x].pb(y);
vv[y].pb(x);
}
dfs(1,0);
int q;
scanf("%d",&q);
for (int i = 1; i <= q; i ++ )
{
int f,x,v;
scanf("%d%d%d",&f,&x,&v);
node[col[x]].pb(Node(i,val[x],x,-1));
if(f == 1)
{
val[x] = v;
}
else
col[x] = v;
node[col[x]].pb(Node(i,val[x],x,1));
}
for(int i = 1; i <= n; i ++ )
node[col[i]].pb(Node(q + 1,val[i],i,-1));
for (int i = 1; i <= n; i ++ )
{
for (int k = 0; k < 20; k ++ )
{
for (int j = 0; j < node[i].size(); j ++ )
{
Node t = node[i][j];
int s = 0;
int f = t.val >> k & 1;
if(f)
{
s = query1(n,0) - query1(R[t.x],0) + query1(L[t.x] - 1,0);
s -= query2(L[t.x],0);
}
else
{
s = query1(n,1) - query1(R[t.x],1) + query1(L[t.x] - 1,1);
s -= query2(L[t.x],1);
}
// printf("%d\n",s);
add1(L[t.x],t.f,f);
add2(L[t.x],t.f,f);
add2(R[t.x] + 1,-t.f,f);
ans[t.id] += 1ll * s * (1 << k) * t.f;
}
}
}
for(int i = 1; i <= q; i ++ )
ans[i] += ans[i - 1];
for (int i = 0; i <= q; i ++ )
{
printf("%lld\n",ans[i]);
ans[i] =0 ;
}
ans[q + 1] = 0;
}
}