题目:http://codeforces.com/contest/593/problem/D
题意:给定一棵n个节点的树。有两种操作:①给定 u v p, 求p除u--->v这条链上所有的边权的值(每次上下取整)②修改某一条边的边权。
分析:
解法一:由于p<=10^18,所以p最多除以60个大于等于2的数就会变为0,当我们遍历一条链的时候只要能避开那些边权为1的边就行了。为每个节点添加一个索引,指向第一个不为1的祖先。初始的时候每个节点的索引指向父亲节点,每次查询的时候顺便压缩一下路径就行了。
具体做法:u-->lca (deep(u)>deep(lca)), v-->lca (deep(v)>deep(lca))
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 1E9+9;
const int maxn = 4e5+6;
struct node
{
int v,next;
LL w;
}List[maxn];
int head[maxn],cnt;
void add(int u,int v,LL w)
{
List[cnt].v=v;
List[cnt].w=w;
List[cnt].next=head[u];
head[u]=cnt++;
}
int anc[200009][20],deep[200009],index[200009];
LL fw[maxn];
void dfs(int cur,int dp)
{
deep[cur]=dp;
for(int i=head[cur];~i;i=List[i].next)
{
int son=List[i].v;
if(anc[cur][0]!=son)
{
anc[son][0]=cur;
fw[son]=List[i].w;
for(int j=1;j<20;j++)
anc[son][j]=anc[anc[son][j-1]][j-1];
dfs(son,dp+1);
}
}
}
int LCA(int a,int b)
{
if(deep[a]<deep[b])
swap(a,b);
int h=deep[a]-deep[b];
for(int i=0;i<20;i++)
if((h>>i)&1)
a=anc[a][i];
if(a==b) return a;
for(int i=19;i>=0;i--)
{
if(anc[a][i]!=anc[b][i])
{
a=anc[a][i];
b=anc[b][i];
}
}
return anc[a][0];
}
pair <int,int> data[maxn];
int main()
{
int n,q,i,j,k,u,v,x,y,tp;
LL w,p;
scanf("%d%d",&n,&q);
memset(head,-1,sizeof(head));
for(i=1;i<n;i++)
{
scanf("%d%d%lld",&u,&v,&w);
data[i]=make_pair(u,v);
add(u,v,w);add(v,u,w);
}
for(i=1;i<=n;i++)
anc[i][0]=1;
dfs(1,0);
for(int i=1;i<=n;i++) //初始指向父亲节点
index[i]=anc[i][0];
while(q--)
{
scanf("%d",&tp);
if(tp==1)
{
scanf("%d%d%lld",&x,&y,&p);
int lca=LCA(x,y);
// printf("lca(%d %d):%d\n",x,y,lca);
while(deep[x]>deep[lca] && p>0)
{
p/=fw[x];
x=(fw[index[x]]>1?index[x]:(index[x]=index[index[x]])); //路径压缩
}
while(deep[y]>deep[lca] && p>0)
{
p/=fw[y];
y=(fw[index[y]]>1?index[y]:(index[y]=index[index[y]]));
}
printf("%lld\n",p);
}
else
{
scanf("%d%lld",&x,&p);
u=data[x].first;
v=data[x].second;
if(anc[u][0]==v)
swap(u,v);
fw[v]=p;
}
}
return 0;
}
解法二:
floor(floor(x/n)/m)=floor(x/(nm))
直接树链剖分,用线段数维护区间乘积,注意溢出。
代码:
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const LL INF = 1e18;
const int maxn = 2e5+7;
int head[maxn],cnt;
struct node
{
int v,next;
}List[maxn<<2];
void add(int u,int v)
{
List[cnt].v=v;
List[cnt].next=head[u];
head[u]=cnt++;
}
int top[maxn],deep[maxn],sz[maxn],fa[maxn],son[maxn],p[maxn],fp[maxn],pos;
int dfs1(int cur,int dp)
{
deep[cur]=dp;
sz[cur]=1;
son[cur]=-1;
for(int i=head[cur];~i;i=List[i].next)
{
int to=List[i].v;
if(fa[cur]!=to)
{
fa[to]=cur;
sz[cur]+=dfs1(to,dp+1);
if(son[cur]==-1 || sz[to]>sz[son[cur]])
son[cur]=to;
}
}
return sz[cur];
}
void dfs2(int cur,int sp)
{
top[cur]=sp;
p[cur]=pos++;
fp[p[cur]]=cur;
if(son[cur]==-1)
return ;
dfs2(son[cur],sp);
for(int i=head[cur];~i;i=List[i].next)
{
int to=List[i].v;
if(to!=son[cur] && fa[cur]!=to)
dfs2(to,to);
}
}
LL tree[maxn<<2];
LL Mul(LL a,LL b)
{
if(a==0 || b==0 || INF/a<b) return 0;
return a*b;
}
void update(int pos,LL v,int l,int r,int rt)
{
if(l==r)
{
tree[rt]=v;
return ;
}
int m=(l+r)>>1;
if(pos<=m)
update(pos,v,lson);
else
update(pos,v,rson);
tree[rt]=Mul(tree[rt<<1],tree[rt<<1|1]);
}
LL query(int L,int R,int l,int r,int rt)
{
if(L<=l && r<=R)
return tree[rt];
int m=(l+r)>>1;
LL ret=1;
if(L<=m)
ret=Mul(ret,query(L,R,lson));
if(R>m)
ret=Mul(ret,query(L,R,rson));
return ret;
}
LL Q(int L,int R)
{
return query(L,R,1,pos,1);
}
LL solve(int u,int v)
{
int f1=top[u],f2=top[v];
LL ret=1;
while(f1!=f2)
{
if(deep[f1]<deep[f2])
{
swap(f1,f2);
swap(u,v);
}
ret=Mul(ret,Q(p[f1],p[u]));
if(!ret) return 0;
u=fa[f1];f1=top[u];
}
if(u==v) return ret;
if(deep[u]>deep[v])
swap(u,v);
return Mul(ret,Q(p[son[u]],p[v]));
}
LL in[maxn][3];
int main()
{
int n,m,i,j,x,y;
LL w;
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
for(i=1;i<n;i++)
{
scanf("%d%d%lld",&x,&y,&w);
add(x,y);add(y,x);
in[i][0]=x;in[i][1]=y;in[i][2]=w;
}
pos=1;
dfs1(1,1);
dfs2(1,1);
for(i=1;i<n;i++)
{
if(deep[in[i][0]]>deep[in[i][1]])
swap(in[i][0],in[i][1]);
update(p[in[i][1]],in[i][2],1,pos,1);
}
while(m--)
{
int tp;
LL val;
scanf("%d",&tp);
if(tp==1)
{
scanf("%d%d%lld",&x,&y,&val);
LL temp=solve(x,y);
if(temp==0) puts("0");
else printf("%lld\n",val/temp);
}
else
{
scanf("%d%lld",&x,&w);
update(p[in[x][1]],w,1,pos,1);
}
}
return 0;
}