题意简述
一棵
n
个点的带权树。F
询问一条路径上所有点的gcd,或C
将一条路径上所有点权
数据范围
1≤n≤50000
1≤ai,d≤1000
思路
如果维护gcd很难维护。
gcd(x,y)=gcd(x,x−y)
我们可以维护差分序列,将区间加转化为单点操作。
每次询问,起始端是原数,后面是差分数列。
再用树状数组维护一下原数。
复杂度
O(nlog3n)
代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define MAXN 50010
struct edge{
int s,t,next;
}e[MAXN<<1];
int head[MAXN],cnt;
void addedge(int s,int t)
{
e[cnt].s=s;e[cnt].t=t;e[cnt].next=head[s];head[s]=cnt++;
e[cnt].s=t;e[cnt].t=s;e[cnt].next=head[t];head[t]=cnt++;
}
int n,ord,u,v,w,q;
char opt;
int deep[MAXN],fa[MAXN],size[MAXN],son[MAXN],top[MAXN],dfn[MAXN],seq[MAXN],a[MAXN];
void dfs1(int node,int lastfa,int de)
{
deep[node]=de;
fa[node]=lastfa;
size[node]=1;
son[node]=0;
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa)
{
dfs1(e[i].t,node,de+1);
size[node]+=size[e[i].t];
if (size[e[i].t]>size[son[node]])
son[node]=e[i].t;
}
}
void dfs2(int node,int lastfa,int tp)
{
top[node]=tp;
dfn[node]=++ord;
seq[ord]=a[node];
if (son[node])
dfs2(son[node],node,tp);
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa&&e[i].t!=son[node])
dfs2(e[i].t,node,e[i].t);
}
int gcd(int a,int b)
{
if (a<0||b<0)
return gcd(abs(a),abs(b));
if (!b)
return a;
return gcd(b,a%b);
}
namespace Segtree
{
struct Node{
int val;
}tree[MAXN<<2];
int pushup(int node)
{
tree[node].val=gcd(tree[node<<1].val,tree[node<<1|1].val);
}
void build(int l,int r,int node)
{
if (l==r)
{
tree[node].val=seq[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
pushup(node);
}
void modify(int pos,int l,int r,int node,int w)
{
if (l==r)
{
tree[node].val+=w;
return;
}
int mid=(l+r)>>1;
if (pos<=mid)
modify(pos,l,mid,node<<1,w);
else
modify(pos,mid+1,r,node<<1|1,w);
pushup(node);
}
int query(int L,int R,int l,int r,int node)
{
if (L<=l&&r<=R)
return tree[node].val;
int mid=(l+r)>>1;
int ret=0;
if (L<=mid)
ret=gcd(ret,query(L,R,l,mid,node<<1));
if (R>mid)
ret=gcd(ret,query(L,R,mid+1,r,node<<1|1));
return ret;
}
}
struct BIT{
static const int size=50000;
int d[50010];
int lowbit(int x)
{
return x&(-x);
}
void modify(int l,int r,int val)
{
for (;l<=size;l+=lowbit(l))
d[l]+=val;
for (++r;r<=size;r+=lowbit(r))
d[r]-=val;
}
int query(int pos)
{
int ret=0;
for (;pos;pos-=lowbit(pos))
ret+=d[pos];
return ret;
}
}T;
void solve_modify(int u,int v,int w)
{
int tu=top[u],tv=top[v],ret=0;
while (tu!=tv)
{
if (deep[tu]<deep[tv])
swap(u,v),swap(tu,tv);
T.modify(dfn[tu],dfn[u],w);
Segtree::modify(dfn[tu],1,n,1,w);
if (dfn[u]+1<=n)
Segtree::modify(dfn[u]+1,1,n,1,-w);
u=fa[tu];
tu=top[u];
}
if (deep[u]>deep[v])
swap(u,v);
T.modify(dfn[u],dfn[v],w);
Segtree::modify(dfn[u],1,n,1,w);
if (dfn[v]+1<=n)
Segtree::modify(dfn[v]+1,1,n,1,-w);
}
int solve_query(int u,int v)
{
int tu=top[u],tv=top[v],ret=0;
while (tu!=tv)
{
if (deep[tu]<deep[tv])
swap(u,v),swap(tu,tv);
ret=gcd(ret,T.query(dfn[tu]));
if (dfn[tu]+1<=dfn[u])
ret=gcd(ret,Segtree::query(dfn[tu]+1,dfn[u],1,n,1));
u=fa[tu];
tu=top[u];
}
if (deep[u]>deep[v])
swap(u,v);
ret=gcd(ret,T.query(dfn[u]));
if (dfn[u]+1<=dfn[v])
ret=gcd(ret,Segtree::query(dfn[u]+1,dfn[v],1,n,1));
return ret;
}
char read()
{
char ch=getchar();
while (ch!='F'&&ch!='C')
ch=getchar();
return ch;
}
int main()
{
scanf("%d",&n);
memset(head,0xff,sizeof(head));
cnt=0;
for (int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
u++,v++;
addedge(u,v);
}
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs1(1,1,1);
dfs2(1,1,1);
for (int i=1;i<=n;i++)
T.modify(i,i,seq[i]);
for (int i=n;i>=1;i--)
seq[i]-=seq[i-1];
Segtree::build(1,n,1);
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
opt=read();
if (opt=='F')
{
scanf("%d%d",&u,&v);
u++,v++;
printf("%d\n",solve_query(u,v));
}
else
{
scanf("%d%d%d",&u,&v,&w);
u++,v++;
solve_modify(u,v,w);
}
}
return 0;
}