裸的树链剖分
线段树里套个堆 最暴力的打法
还有一种做法是考虑二分答案,如果大于答案的边都经过询问点,则往小的二分否则往大的二分。这样我们只要维护路径的交集。用rmq求lca的话可以做到O(1)求出两条路径的交集。可以离散后用线段树维护二分结构,并在对应的节点上记录路径交集
#include<cstdio> #include<cstdlib> #include<algorithm> #include<queue> #define V G[p].v #define oo 1<<30 using namespace std; typedef pair<int,int> abcd; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } struct Heap{ priority_queue<int> H,Del; bool empty(){ return H.size()-Del.size()==0; } int top() { while (!Del.empty() && Del.top()==H.top()) H.pop(),Del.pop(); if (H.empty()) return -oo; else return H.top(); } void push(int x) { H.push(x); } void erase(int x) { Del.push(x); } }; const int N=100005; struct SEGTREE{ Heap T[4*N]; int M,TH; void Build(int n){ for (M=1;M<n+2;M<<=1); } void add(int s,int t,int r){ for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1) { if (~s&1) T[s^1].push(r); if ( t&1) T[t^1].push(r); } } void del(int s,int t,int r){ for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1) { if (~s&1) T[s^1].erase(r); if ( t&1) T[t^1].erase(r); } } int query(int s){ int ret=-oo; ret=max(ret,T[s+=M].top()); while (s>>=1) ret=max(ret,T[s].top()); return ret; } }Seg; struct edge{ int u,v,next; }; edge G[2*N]; int head[N],inum; inline void add(int u,int v,int p){ G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p; } int size[N],depth[N],fat[N]; int clk,tid[N],top[N]; void dfs(int u,int fa){ fat[u]=fa; depth[u]=depth[fa]+1; size[u]=1; for (int p=head[u];p;p=G[p].next) if (V!=fa) dfs(V,u),size[u]+=size[V]; } void find(int u,int fa,int z){ tid[u]=++clk; top[u]=z; int maximum=0,son=0; for (int p=head[u];p;p=G[p].next) if (V!=fa && size[V]>maximum) maximum=size[son=V]; if (son) find(son,u,z); for (int p=head[u];p;p=G[p].next) if (V!=fa && V!=son) find(V,u,V); } int n; int _u[N],_v[N],_w[N]; abcd path[N]; int pcnt; inline void deal(int l,int r,int w,int f) { if (l>r) return; if (f==1) Seg.add(l,r,w); else Seg.del(l,r,w); } inline void Modify(int u,int v,int w,int f) { pcnt=0; for (;top[u]!=top[v];u=fat[top[u]]) { if (depth[top[u]]<depth[top[v]]) swap(u,v); path[++pcnt]=abcd(tid[top[u]],tid[u]); } if (depth[u]>depth[v]) swap(u,v); path[++pcnt]=abcd(tid[u],tid[v]); sort(path+1,path+pcnt+1); deal(1,path[1].first-1,w,f); for (int i=1;i<pcnt;i++) deal(path[i].second+1,path[i+1].first-1,w,f); deal(path[pcnt].second+1,n,w,f); } inline int Query(int x){ int ret=Seg.query(tid[x]); if (ret==-oo) return -1; return ret; } int main() { int Q,iu,iv,iw,order; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(Q); for (int i=1;i<n;i++) read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum); dfs(1,0); find(1,0,1); Seg.Build(n); for (int i=1;i<=Q;i++) { read(order); if (order==0) read(_u[i]),read(_v[i]),read(_w[i]),Modify(_u[i],_v[i],_w[i],1); else if (order==1) read(iw),Modify(_u[iw],_v[iw],_w[iw],-1); else if (order==2) read(iw),printf("%d\n",Query(iw)); } return 0; }