pku2763 Housewife Wind
题意:给定一棵有n( n < 100001 )个结点的带边权的树,处理以下一共q(q < 100001)个操作:
1,改变树的一条边的权;
2,求给定点和某点的距离,后者是编号为1的结点,若是第一次执行操作2,否则为上次执行操作2的给定点。
没有了操作1,这题就是典型的LCA,于是怎样有效地执行操作1就是这题的关键。还记得LCA到RMQ的转化吗点我,过程中DFS会生成一条回路,并且产生一个从遍历次序到结点编号的满射,我们称它为order[]。我们知道,若以结点到根的距离作为树的深度,如果一条边的权增加了delta,那么这条边链接的子树内的所有结点的深度都增加了delta。又因为子树内的结点的遍历次序是连续的,所以我们可以建立从 遍历次序 到 到根的距离的映射dist[],于是每次执行操作1只需对dist[]的一片连续区域作修改即可,可以用线段树或者树状数组。
搞定了操作1,我们发现操作2也被搞出来了,因为LCA(u,v)=order[RMQ(dist[出现u的任意遍历序号...出现v的任意遍历序号])],可能这是出题者的意图吧。
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
#define MAXN 200005
#define LOG 20
typedef pair<int,int> PAIR;
int order[MAXN],ecnt,dist[MAXN],first[MAXN],last[MAXN],n,q,st,p[MAXN],maxorder,c[MAXN],mn[MAXN][LOG],b[MAXN];
//first[u]表示u首次出现的遍历序号,last[u]表示u最后出现的遍历序号
bool visited[MAXN];
struct Edge{
int v,weight,next;
}edg[MAXN];
void init(){
ecnt=0;
memset(p,-1,sizeof(p));
memset(dist,0,sizeof(dist));
maxorder=1;
memset(visited,false,sizeof(visited));
memset(c,0,sizeof(c));
}
void dfs(int pre,int u,int w){
int i,v,ordertmp;
visited[u]=true;
last[u]=first[u]=maxorder;
order[maxorder]=u;
dist[maxorder]=dist[last[pre]]+w;
ordertmp=maxorder++;
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(!visited[v]){
dfs(u,v,edg[i].weight);
order[maxorder]=u;
last[u]=maxorder;
dist[maxorder]=dist[ordertmp];
maxorder++;
}
}
}
//////////////////////////////////////////////////////////////////////////
//树状数组
inline int lowbit(int x){
return x&(-x);
}
int down(int x){
int i,res=0;
for(i=x;i>0;i-=lowbit(i))
res+=c[i];
return res;
}
void up(int x,int t){
int i;
for(i=x;i<maxorder;i+=lowbit(i))
c[i]+=t;
}
void build(){
int i;
for(i=1;i<maxorder;i++)
b[i]=dist[i]-dist[i-1];
for(i=1;i<maxorder;i++){
up(i,b[i]);
}
}
//////////////////////////////////////////////////////////////////////////
//spares table
void preprocess(){
int i,j;
for(i=1;i<maxorder;i++)
mn[i][0]=i;
for(j=1;(1<<j)<=maxorder;j++){
for(i=1;i+(1<<j)-1<maxorder;i++){
if(dist[mn[i][j-1]]<=dist[mn[i+(1<<(j-1))][j-1]])
mn[i][j]=mn[i][j-1];
else
mn[i][j]=mn[i+(1<<(j-1))][j-1];
}
}
}
int RMQ(int i,int j){
if(i>j){
int t=i;
i=j;
j=t;
}
int k=log((double)j-i+1)/log((double)2);
if(dist[mn[i][k]]<=dist[mn[j-(1<<k)+1][k]])
return mn[i][k];
else
return mn[j-(1<<k)+1][k];
}
//////////////////////////////////////////////////////////////////////////
//main
int main(){
int i,j,u,v,weight,flag,w;
init();
vector<PAIR> vec;
scanf("%d%d%d",&n,&q,&st);
for(i=0;i<n-1;i++){
scanf("%d%d%d",&u,&v,&weight);
vec.push_back(make_pair(u,v));
edg[ecnt].next=p[u];
edg[ecnt].v=v;
edg[ecnt].weight=weight;
p[u]=ecnt++;
edg[ecnt].next=p[v];
edg[ecnt].v=u;
edg[ecnt].weight=weight;
p[v]=ecnt++;
}
dfs(1,1,0);
// for(i=1;i<maxorder;i++)
// printf("%d ",order[i]);
// printf("\n");
// for(i=1;i<maxorder;i++)
// printf("%d ",dist[i]);
// printf("\n");
// for(i=1;i<=n;i++)
// printf("%d ",first[i]);
// printf("\n");
// for(i=1;i<=n;i++)
// printf("%d ",last[i]);
// printf("\n");
build();
preprocess();
for(i=0;i<q;i++){
scanf("%d",&flag);
if(flag){
scanf("%d%d",&j,&weight);
j--;
u=vec[j].first;
v=vec[j].second;
if(dist[first[u]]>dist[first[v]]){
int t=u;
u=v;
v=t;
}
w=down(first[v])-down(first[u]);
up(first[v],weight-w);
if(last[v]+1<maxorder)
up(last[v]+1,w-weight);
}
else{
scanf("%d",&u);
v=order[RMQ(first[u],first[st])];
printf("%d\n",down(first[u])+down(first[st])-2*down(first[v]));
st=u;
}
}
return 0;
}
#include <vector>
#include <cmath>
using namespace std;
#define MAXN 200005
#define LOG 20
typedef pair<int,int> PAIR;
int order[MAXN],ecnt,dist[MAXN],first[MAXN],last[MAXN],n,q,st,p[MAXN],maxorder,c[MAXN],mn[MAXN][LOG],b[MAXN];
//first[u]表示u首次出现的遍历序号,last[u]表示u最后出现的遍历序号
bool visited[MAXN];
struct Edge{
int v,weight,next;
}edg[MAXN];
void init(){
ecnt=0;
memset(p,-1,sizeof(p));
memset(dist,0,sizeof(dist));
maxorder=1;
memset(visited,false,sizeof(visited));
memset(c,0,sizeof(c));
}
void dfs(int pre,int u,int w){
int i,v,ordertmp;
visited[u]=true;
last[u]=first[u]=maxorder;
order[maxorder]=u;
dist[maxorder]=dist[last[pre]]+w;
ordertmp=maxorder++;
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(!visited[v]){
dfs(u,v,edg[i].weight);
order[maxorder]=u;
last[u]=maxorder;
dist[maxorder]=dist[ordertmp];
maxorder++;
}
}
}
//////////////////////////////////////////////////////////////////////////
//树状数组
inline int lowbit(int x){
return x&(-x);
}
int down(int x){
int i,res=0;
for(i=x;i>0;i-=lowbit(i))
res+=c[i];
return res;
}
void up(int x,int t){
int i;
for(i=x;i<maxorder;i+=lowbit(i))
c[i]+=t;
}
void build(){
int i;
for(i=1;i<maxorder;i++)
b[i]=dist[i]-dist[i-1];
for(i=1;i<maxorder;i++){
up(i,b[i]);
}
}
//////////////////////////////////////////////////////////////////////////
//spares table
void preprocess(){
int i,j;
for(i=1;i<maxorder;i++)
mn[i][0]=i;
for(j=1;(1<<j)<=maxorder;j++){
for(i=1;i+(1<<j)-1<maxorder;i++){
if(dist[mn[i][j-1]]<=dist[mn[i+(1<<(j-1))][j-1]])
mn[i][j]=mn[i][j-1];
else
mn[i][j]=mn[i+(1<<(j-1))][j-1];
}
}
}
int RMQ(int i,int j){
if(i>j){
int t=i;
i=j;
j=t;
}
int k=log((double)j-i+1)/log((double)2);
if(dist[mn[i][k]]<=dist[mn[j-(1<<k)+1][k]])
return mn[i][k];
else
return mn[j-(1<<k)+1][k];
}
//////////////////////////////////////////////////////////////////////////
//main
int main(){
int i,j,u,v,weight,flag,w;
init();
vector<PAIR> vec;
scanf("%d%d%d",&n,&q,&st);
for(i=0;i<n-1;i++){
scanf("%d%d%d",&u,&v,&weight);
vec.push_back(make_pair(u,v));
edg[ecnt].next=p[u];
edg[ecnt].v=v;
edg[ecnt].weight=weight;
p[u]=ecnt++;
edg[ecnt].next=p[v];
edg[ecnt].v=u;
edg[ecnt].weight=weight;
p[v]=ecnt++;
}
dfs(1,1,0);
// for(i=1;i<maxorder;i++)
// printf("%d ",order[i]);
// printf("\n");
// for(i=1;i<maxorder;i++)
// printf("%d ",dist[i]);
// printf("\n");
// for(i=1;i<=n;i++)
// printf("%d ",first[i]);
// printf("\n");
// for(i=1;i<=n;i++)
// printf("%d ",last[i]);
// printf("\n");
build();
preprocess();
for(i=0;i<q;i++){
scanf("%d",&flag);
if(flag){
scanf("%d%d",&j,&weight);
j--;
u=vec[j].first;
v=vec[j].second;
if(dist[first[u]]>dist[first[v]]){
int t=u;
u=v;
v=t;
}
w=down(first[v])-down(first[u]);
up(first[v],weight-w);
if(last[v]+1<maxorder)
up(last[v]+1,w-weight);
}
else{
scanf("%d",&u);
v=order[RMQ(first[u],first[st])];
printf("%d\n",down(first[u])+down(first[st])-2*down(first[v]));
st=u;
}
}
return 0;
}