//#include<bits/stdc++.h> //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<set> #include<map> #include<vector> #include<iomanip> using namespace std; #define ll long long #define pb push_back const int maxn=1e6+7; const int inf=0x3f3f3f3f; struct EDGE{ int u,v,val,next; }G[maxn<<1]; int tot;int head[maxn]; void init(){ memset(head,-1,sizeof head);tot=0; } void addedge(int u,int v,int w){ tot++;G[tot]={u,v,w,head[u]};head[u]=tot; } int vs[maxn<<1]; int in[maxn],out[maxn]; int tim; int dep[maxn<<1]; int id[maxn]; int pre[maxn]; void dfs(int u,int fa,int d){ pre[u]=fa; id[u]=++tim;vs[tim]=u;dep[tim]=d; in[u]=tim;out[u]=tim; for(int i=head[u];~i;i=G[i].next){ EDGE e=G[i]; if(e.v==fa)continue; dfs(e.v,u,d+e.val); vs[++tim]=u;dep[tim]=d;out[u]=tim; } } struct node{ int fa; //区间内公共祖先 int mindep; int add; //lazy }ST[maxn<<2]; void pushdown(int rt){ if(ST[rt].add){ ST[rt<<1].mindep+=ST[rt].add;ST[rt<<1|1].mindep+=ST[rt].add; ST[rt<<1].add+=ST[rt].add;ST[rt<<1|1].add+=ST[rt].add; ST[rt].add=0; } } void pushup(int rt){ if(ST[rt<<1].mindep<=ST[rt<<1|1].mindep){ ST[rt].mindep=ST[rt<<1].mindep; ST[rt].fa=ST[rt<<1].fa; }else{ ST[rt].mindep=ST[rt<<1|1].mindep; ST[rt].fa=ST[rt<<1|1].fa; } } void build(int l,int r,int rt){ if(l==r){ ST[rt].mindep=dep[l]; ST[rt].fa=vs[l]; ST[rt].add=0; return; } ST[rt].add=0; int m=l+r>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); pushup(rt); } void update(int a,int b,int c,int l,int r,int rt){ if(a<=l&&b>=r){ ST[rt].mindep+=c; ST[rt].add+=c; return; } pushdown(rt); int m=l+r>>1; if(a<=m)update(a,b,c,l,m,rt<<1); if(b>m)update(a,b,c,m+1,r,rt<<1|1); pushup(rt); } node query(int a,int b,int l,int r,int rt){ //查询a-b内的祖先 //cout<<a<<" "<<b<<" "<<l<<" "<<r<<endl; if(a<=l&&b>=r){ return ST[rt]; } pushdown(rt); int m=l+r>>1; node n2={0,inf,0},n1={0,inf,0}; if(a<=m)n1=query(a,b,l,m,rt<<1); if(b> m)n2=query(a,b,m+1,r,rt<<1|1); if(n1.mindep<n2.mindep){return n1;} else return n2; } int main(){ int n,q,s; while(~scanf("%d%d%d",&n,&q,&s)){ init(); for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); //if(u>v)swap(u,v); addedge(u,v,w); addedge(v,u,w); } int now=s; tim=0; dep[s]=0; dfs(s,s,0); build(1,tim,1); for(int i=1;i<=q;i++){ int kind;int a,b; scanf("%d",&kind); if(kind){ //改边 scanf("%d%d",&a,&b); a=2*a-1; int flag=0; if(pre[G[a].v]==G[a].u){flag=1;} else a++; EDGE e=G[a]; int plus=b-e.val; update(in[e.v],out[e.v],plus,1,tim,1); if(flag){ G[a].val=b; G[a+1].val=b; }else{ G[a].val=b; G[a-1].val=b; } //for(int i=1;i<=tim;i++){ // cout<<vs[i]<<"ss"<<endl; //} }else{ scanf("%d",&a); //cout<<now<<" "<<a<<endl; node anc= query(min(id[a],id[now]),max(id[now],id[a]),1,tim,1); node n1,n2; n1=query(id[now],id[now],1,tim,1); n2=query(id[a],id[a],1,tim,1); int ans=n1.mindep+n2.mindep-anc.mindep*2; //cout<<n1.mindep<<" "<<n2.mindep<<" "<<anc.mindep<<endl; //cout<<n1.fa<<" "<<n2.fa<<" "<<anc.fa<<endl; printf("%d ",ans); now=a; } } } } /* 3 100 2 1 2 6 1 3 5 1 1 4 0 1 */
核心就是vs序列存下的in[u],out[u]的中间段只有u的子树
做法肯定不是最优的,因为检查每个节点的深度我都用到了线段树查询,慢了3倍
换上树状数组肯定能更快,但我懒得学。。
双向边的编号修改难死我了。。。还好想出办法解决了
(其实是别人的代码我看不懂