BZOJ 4538 网络 发表于 2017-03-23 | 更新于 2018-06-18 LinkSolution因为询问的是不覆盖一个点的路径 那么就把修改也转化成补集,可以通过树剖DFS序解决 感觉并不是很难想,但就是想不到。。树剖DFS序看起来有无限可能。 Code123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175#include "lucida"using std::priority_queue;using std::swap;using std::sort;using std::pair;const int MAXN=1e5+11,MAXM=2e5+11;struct Edge { int to;Edge *pre; Edge(int to,Edge *pre):to(to),pre(pre) {} void *operator new(size_t) { static Edge *Me=alloc(Edge,MAXN<<1); return Me++; }}*G[MAXN];void Adde(int f,int t) { G[f]=new Edge(t,G[f]); G[t]=new Edge(f,G[t]);}struct MagicHeap { priority_queue<int> app,rmv; void Maintain() { while(!app.empty() && !rmv.empty() && app.top()==rmv.top()) { app.pop(); rmv.pop(); } } int Top() { Maintain(); return !app.empty()?app.top():-1; } void Push(int x) { Maintain(); app.push(x); } void Remove(int x) {//app中必须有! Maintain(); rmv.push(x); }};namespace segtree { struct Node { Node *son[2]; MagicHeap heap; Node() { son[0]=son[1]=0; } void *operator new(size_t) { static Node *Me=alloc(Node,MAXN<<2); return Me++; } }; struct SegTree { Node *root; int L,R; void Build(Node *&pos,int L,int R) { pos=new Node; if(L!=R) { int Mid=(L+R)>>1; Build(pos->son[0],L,Mid); Build(pos->son[1],Mid+1,R); } } void Edit(Node *pos,int L,int R,int l,int r,int v) { if(l<=L && R<=r) v>0?pos->heap.Push(v):pos->heap.Remove(-v); else { int Mid=(L+R)>>1; if(l<=Mid) Edit(pos->son[0],L,Mid,l,r,v); if(Mid+1<=r) Edit(pos->son[1],Mid+1,R,l,r,v); } } int Access(Node *pos,int L,int R,int goal) { int res=pos->heap.Top(); if(L!=R) { int Mid=(L+R)>>1; if(goal<=Mid) chkmx(res,Access(pos->son[0],L,Mid,goal)); else chkmx(res,Access(pos->son[1],Mid+1,R,goal)); } return res; } SegTree() {} SegTree(int L,int R):L(L),R(R) { Build(root,L,R); } void Edit(int l,int r,int v) {//正数插入 负数删除相反数 if(l<=r) Edit(root,L,R,l,r,v); } int Query(int pos) { return Access(root,L,R,pos); } };}using segtree::SegTree;namespace divide { SegTree seg; int cht[MAXN],dep[MAXN],sz[MAXN],fa[MAXN],prefer[MAXN],dfs[MAXN],lbd[MAXN],rbd[MAXN],dc; void DFS(int pos) { sz[pos]=1;dep[pos]=dep[fa[pos]]+1; for(Edge *e=G[pos];e;e=e->pre) if(fa[pos]!=e->to) { int u=e->to; fa[u]=pos; DFS(u); sz[pos]+=sz[u]; if(sz[u]>=sz[prefer[pos]]) prefer[pos]=u; } } void Assign(int pos,int top) { cht[pos]=top; dfs[++dc]=pos; lbd[pos]=dc; if(prefer[pos]) { Assign(prefer[pos],top); for(Edge *e=G[pos];e;e=e->pre) if(e->to!=fa[pos] && e->to!=prefer[pos]) { int u=e->to; Assign(u,u); } } rbd[pos]=dc; } void Divide() { DFS(1); Assign(1,1); new(&seg) SegTree(1,dc); } void CpChain(int p1,int p2,int v) { static pair<int,int> range[MAXN]; int rc=0; while(cht[p1]!=cht[p2]) { if(dep[cht[p1]]<dep[cht[p2]]) swap(p1,p2); range[++rc]=pair<int,int>(lbd[cht[p1]],lbd[p1]); p1=fa[cht[p1]]; } if(dep[p1]>dep[p2]) swap(p1,p2); range[++rc]=pair<int,int>(lbd[p1],lbd[p2]); sort(range+1,range+1+rc); seg.Edit(1,range[1].first-1,v); for(int i=2;i<=rc;++i) seg.Edit(range[i-1].second+1,range[i].first-1,v); seg.Edit(range[rc].second+1,dc,v);//没有判后面这一部分 } int Query(int x) { return seg.Query(lbd[x]); }}using namespace divide;int main() {// freopen("input","r",stdin); int n,m;is>>n>>m; for(int i=1;i<=n-1;++i) { int x,y;is>>x>>y; Adde(x,y); } Divide(); static struct {int a,b,v;}op[MAXM]; for(int i=1;i<=m;++i) { int opt,t,x;is>>opt; switch(opt) { case 0: is>>op[i].a>>op[i].b>>op[i].v; CpChain(op[i].a,op[i].b,op[i].v); break; case 1: is>>t; CpChain(op[t].a,op[t].b,-op[t].v); break; case 2: is>>x; os<<Query(x)<<'\n'; break; } } return 0;}