杭电多校第三场 Tokitsukaze and Colorful Tree 树

Tokitsukaze and Colorful Tree

题目链接

题目大意

给一颗树,每个点有颜色、权值。
杭电多校第三场 Tokitsukaze and Colorful Tree 树_第1张图片
的值。
这个式子就是颜色相同的,并且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
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;
	}
}

你可能感兴趣的:(做题笔记)