好久之前写的题了。现在要重新开始写题解了。就从这题开始吧。
题意:一棵树,两点之间的权值为路径上的值异或得到,求任意两点之间的权值和,有修改操作,每次都要输出任意两点间的权值和。
做法:当时写这题写了好久。就说下一些关键的思路,因为细节部分真的是太多。首先不同的位独立考虑,然后任意两点我们肯定会想到点分治,点分治时会dfs求出子树里每个点到根节点的权值,然后进行配对求经过根节点的权值和。
那么这个题我们可以把分治的的过程给保存下来,因为修改一个点的权值就意味着在某一个点分治的阶段,那个点其下的点到根节点的权值全都异或1(因为按位不同考虑,假设那个位跟原来不一样)。所以可以弄出dfs序,然后区间更新即可。然后每一次分治的根节点我们要保存:其下1和0的个数,1和1配对的个数,0个0配对的个数,1和0配对的个数。那么在修改时,我们先把那颗子树上0和1对于这个根节点的贡献给消除,再去在子树上区间更新得到新的0和1的个数,再去重新计算根节点我要维护的那几个值。这样答案就可以重新知道了。
具体思路就是这样,但是比较繁琐,比如得维护每个点的每一次分治是属于哪个线段树,以及它在这个线段树中所能影响的范围(即他的子树dfs序的范围)。以及每次分治过程根节点的信息(就是刚才说的)。细节注意下就可以了。
PS:8.5k的代码也是写的很醉人。
AC代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll __int64
#define ull unsigned __int64
#define eps 1e-8
#define NMAX 30000
#define MOD 998244353
//#define lson l,mid,rt<<1,d
//#define rson mid+1,r,rt<<1|1,d
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
char c;
int flag = 0;
ret=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c == '-')
{
flag = 1;
c = getchar();
}
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
if(flag) ret = -ret;
}
const int maxn = 10000+10;
struct Edge
{
int v,next;
}e[maxn*2];
int head[maxn],ecnt;
void add_edge(int u, int v)
{
e[ecnt].v = v;
e[ecnt].next = head[u];
head[u] = ecnt++;
}
int point;
int Pos[maxn],Size[maxn];
int dp[maxn],mi,pp,sz;
struct Tree
{
int zero,one,zz,oo,zo;
}Tree[15][maxn];
int ans[15];
bool data[15][maxn],vis[maxn];
void gao1(int u, int fa)
{
dp[u] = 1;
sz++;
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].v;
if(v == fa || vis[v]) continue;
gao1(v,u);
dp[u] += dp[v];
}
}
void gao2(int u, int fa)
{
int tmp = sz-dp[u];
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].v;
if(v == fa || vis[v]) continue;
gao2(v,u);
tmp = max(tmp,dp[v]);
}
if(tmp < mi)
{
mi = tmp;
pp = u;
}
}
int getbarycenter(int u)
{
sz = 0;
gao1(u,u);
mi = 1000000;
gao2(u,u);
return pp;
}
struct node
{
int root, ge, l, r;
node(){}
node(int _root, int _ge, int _l, int _r):root(_root),ge(_ge),l(_l),r(_r) {}
};
vector<node>vec[maxn];
bool a[15][maxn];
void solve(int u, int fa, int w, int rt, int tou, int flag)
{
sz++;
a[flag][sz] = w;
int tmp = sz;
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].v;
if(v == fa || vis[v]) continue;
solve(v,u,w^data[flag][v],rt,tou,flag);
}
if(flag == 0) vec[u].push_back(node(rt,tou,tmp,sz));
}
int tot;
int lson[maxn*30],rson[maxn*30];
struct SegmentTree
{
int zero,one;
bool flag;
}T[15][maxn*30];
int build(int l, int r)
{
int rt = ++tot;
for(int i = 0; i <= 14; i++)
T[i][rt].flag = 0;
if(l == r)
{
// T[rt].lson = T[rt].rson = 0;
for(int i = 0; i <= 14; i++)
{
T[i][rt].zero = T[i][rt].one = 0;
if(a[i][l] == 1) T[i][rt].one = 1;
else T[i][rt].zero = 1;
}
return rt;
}
int mid = (l+r)>>1;
lson[rt] = build(l,mid);
rson[rt] = build(mid+1,r);
for(int i = 0; i <= 14; i++)
{
T[i][rt].one = T[i][lson[rt]].one + T[i][rson[rt]].one;
T[i][rt].zero = T[i][lson[rt]].zero + T[i][rson[rt]].zero;
}
return rt;
}
void dfs(int u)
{
u = getbarycenter(u);
// cout<<"tree:"<<u<<" "<<sz<<endl;
if(sz == 1)
{
for(int i = 0; i <= 14; i++)
Tree[i][u].one = Tree[i][u].zero = Tree[i][u].oo = Tree[i][u].zz = Tree[i][u].zo = 0;
// vec[u].push_back(node(u,0,0,0));
return;
}
int z[15] = {0}, o[15] = {0}, oo[15] = {0}, zz[15] = {0}, zo[15] = {0};
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].v;
if(vis[v]) continue;
for(int j = 0; j <= 14; j++)
{
sz = 0;
solve(v,u,data[j][v],u,point,j);
}
int pos = build(1,sz);
// cout<<"shit1:"<<v<<" "<<sz<<" "<<T[0][pos].one<<endl;
Pos[point] = pos;
Size[point++] = sz;
for(int j = 0; j <= 14; j++)
{
oo[j] += T[j][pos].one*o[j];
zz[j] += T[j][pos].zero*z[j];
zo[j] += T[j][pos].one*z[j]+T[j][pos].zero*o[j];
o[j] += T[j][pos].one;
z[j] += T[j][pos].zero;
}
}
for(int i = 0; i <= 14; i++)
{
Tree[i][u].one = o[i];
Tree[i][u].zero = z[i];
Tree[i][u].oo = oo[i];
Tree[i][u].zz = zz[i];
Tree[i][u].zo = zo[i];
if(data[i][u] == 1) ans[i] += oo[i]+zz[i]+z[i];
else ans[i] += zo[i]+o[i];
}
vis[u] = 1;
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].v;
if(vis[v]) continue;
dfs(v);
}
}
void init(int n)
{
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
for(int i = 1; i <= n; i++)
vec[i].clear();
}
void pushdown(int rt, int flag)
{
if(T[flag][rt].flag)
{
swap(T[flag][lson[rt]].zero,T[flag][lson[rt]].one);
swap(T[flag][rson[rt]].zero,T[flag][rson[rt]].one);
T[flag][lson[rt]].flag ^= 1;
T[flag][rson[rt]].flag ^= 1;
T[flag][rt].flag = 0;
}
}
void update(int L, int R, int l, int r, int rt, int flag)
{
if(L <= l && R >= r)
{
T[flag][rt].flag ^= 1;
swap(T[flag][rt].zero,T[flag][rt].one);
return;
}
pushdown(rt,flag);
int mid = (l+r)>>1;
if(L <= mid) update(L,R,l,mid,lson[rt],flag);
if(R > mid) update(L,R,mid+1,r,rson[rt],flag);
T[flag][rt].one = T[flag][lson[rt]].one + T[flag][rson[rt]].one;
T[flag][rt].zero = T[flag][lson[rt]].zero + T[flag][rson[rt]].zero;
}
void rilegou(int x, int flag)
{
int num = vec[x].size();
for(int i = 0; i < num; i++)
{
int rt = vec[x][i].root,ge = vec[x][i].ge;
if(data[flag][rt] == 1) ans[flag] -= Tree[flag][rt].zero+Tree[flag][rt].oo+Tree[flag][rt].zz;
else ans[flag] -= Tree[flag][rt].one+Tree[flag][rt].zo;
int z = T[flag][Pos[ge]].zero, o = T[flag][Pos[ge]].one;
Tree[flag][rt].oo -= (Tree[flag][rt].one-o)*o;
Tree[flag][rt].zz -= (Tree[flag][rt].zero-z)*z;
Tree[flag][rt].zo -= (Tree[flag][rt].one-o)*z+(Tree[flag][rt].zero-z)*o;
Tree[flag][rt].one -= o;
Tree[flag][rt].zero -= z;
update(vec[x][i].l,vec[x][i].r,1,Size[ge],Pos[ge],flag);
z = T[flag][Pos[ge]].zero;
o = T[flag][Pos[ge]].one;
Tree[flag][rt].oo += o*Tree[flag][rt].one;
Tree[flag][rt].zz += z*Tree[flag][rt].zero;
Tree[flag][rt].zo += o*Tree[flag][rt].zero+z*Tree[flag][rt].one;
Tree[flag][rt].one += o;
Tree[flag][rt].zero += z;
if(data[flag][rt] == 1) ans[flag] += Tree[flag][rt].zero+Tree[flag][rt].oo+Tree[flag][rt].zz;
else ans[flag] += Tree[flag][rt].one+Tree[flag][rt].zo;
}
if(data[flag][x] == 1)
{
ans[flag] -= Tree[flag][x].zero+Tree[flag][x].oo+Tree[flag][x].zz;
ans[flag] += Tree[flag][x].one+Tree[flag][x].zo;
data[flag][x] = 0;
}
else
{
ans[flag] -= Tree[flag][x].one+Tree[flag][x].zo;
ans[flag] += Tree[flag][x].zero+Tree[flag][x].oo+Tree[flag][x].zz;
data[flag][x] = 1;
}
}
int main()
{
#ifdef GLQ
freopen("input.txt","r",stdin);
// freopen("o.txt","r",stdin);
#endif
int n,q;
while(~scanf("%d%d",&n,&q))
{
memset(head,-1,sizeof(head));
ecnt = point = tot = 0;
init(n);
for(int i = 1; i <= n; i++)
{
int tmp;
scanf("%d",&tmp);
for(int j = 0; j <= 14; j++)
data[j][i] = !!(tmp&(1<<j));
}
for(int i = 1; i < n; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs(1);
// cout<<vec[2].size()<<endl;
ll ret = 0;
for(int i = 0; i <= 14; i++)
ret += (ll)ans[i]*(1LL<<i);
// cout<<ret<<endl;
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
for(int i = 0; i <= 14; i++)
{
if(data[i][x] == !!(y&(1<<i))) continue;
ret -= (ll)ans[i]*(1LL<<i);
rilegou(x,i);
ret += (ll)ans[i]*(1LL<<i);
}
printf("%I64d\n",ret*2LL);
}
}
return 0;
}