[HNOI2016]网络
题目大意:
给你一棵$n(n\leq10^5)$的数,有$m(m\leq2\times10^5)$次操作,操作包含以下三种:
1.新建一个从$u$到$v$的任务,权值为$w$;
2.删除第$i$个任务;
3.询问所有不经过$x$的任务中最大的权值。
思路:
树链剖分线段树套二叉堆。
首先对树进行轻重链剖分,建立线段树。每个线段树结点套二叉堆,维护不经过这个结点的权值。因此对于操作1,我们可以先求LCA,同时求出路径上经过的所有链,修改没有经过的那一些链。对于操作2,暴力删除肯定会TLE,考虑另建一个堆来维护删除的那些权值。因此对于操作3,我们在取top时,先比较一下两个堆的top是否相同,如果相同就忽略掉。树链剖分LCA复杂度$O(\log n)$,线段树复杂度$O(\log n)$,二叉堆复杂度$O(\log m)$,时间复杂度$O(m\log^2 n\log m)$。
细节:
二叉堆不能够用pb_ds中的配对堆代替,会MLE。
1 #include<list> 2 #include<queue> 3 #include<cstdio> 4 #include<cctype> 5 #include<vector> 6 #include<algorithm> 7 inline int getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 const int N=100001,M=200001; 15 std::list<int> e[N]; 16 inline void add_edge(const int &u,const int &v) { 17 e[u].push_back(v); 18 e[v].push_back(u); 19 } 20 int dep[N],par[N],top[N],dfn[N],size[N],son[N]; 21 void dfs1(const int &x,const int &par) { 22 size[x]=1; 23 dep[x]=dep[::par[x]=par]+1; 24 for(register std::list<int>::iterator i=e[x].begin();i!=e[x].end();i++) { 25 const int &y=*i; 26 if(y==par) continue; 27 dfs1(y,x); 28 size[x]+=size[y]; 29 if(size[y]>size[son[x]]) son[x]=y; 30 } 31 } 32 void dfs2(const int &x) { 33 dfn[x]=++dfn[0]; 34 top[x]=x==son[par[x]]?top[par[x]]:x; 35 if(son[x]) dfs2(son[x]); 36 for(register std::list<int>::iterator i=e[x].begin();i!=e[x].end();i++) { 37 const int &y=*i; 38 if(y==par[x]||y==son[x]) continue; 39 dfs2(y); 40 } 41 } 42 class SegmentTree { 43 #define _left <<1 44 #define _right <<1|1 45 private: 46 std::priority_queue<int> val[N<<2][2]; 47 public: 48 void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x,const int &type) { 49 if(b==l&&e==r) { 50 val[p][type].push(x); 51 return; 52 } 53 const int mid=(b+e)>>1; 54 if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x,type); 55 if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x,type); 56 } 57 int query(const int &p,const int &b,const int &e,const int &x) { 58 int ret=-1; 59 while(!val[p][0].empty()&&val[p][0].top()==val[p][1].top()) { 60 val[p][0].pop(); 61 val[p][1].pop(); 62 } 63 if(!val[p][1].empty()) ret=val[p][1].top(); 64 if(b==e) return ret; 65 const int mid=(b+e)>>1; 66 if(x<=mid) ret=std::max(ret,query(p _left,b,mid,x)); 67 if(x>mid) ret=std::max(ret,query(p _right,mid+1,e,x)); 68 return ret; 69 } 70 #undef _left 71 #undef _right 72 }; 73 SegmentTree t; 74 struct Path { 75 int u,v,w; 76 }; 77 Path p[M]; 78 std::vector<std::pair<int,int> > s; 79 inline void modify(const int &id,const int &type) { 80 int u=p[id].u,v=p[id].v; 81 while(top[u]!=top[v]) { 82 if(dep[top[u]]<dep[top[v]]) std::swap(u,v); 83 s.push_back(std::make_pair(dfn[top[u]],dfn[u])); 84 u=par[top[u]]; 85 } 86 if(dep[u]<dep[v]) std::swap(u,v); 87 s.push_back(std::make_pair(dfn[v],dfn[u])); 88 s.push_back(std::make_pair(0,0)); 89 std::sort(s.begin(),s.end()); 90 s.push_back(std::make_pair(dfn[0]+1,0)); 91 for(register unsigned i=1;i<s.size();i++) { 92 if(s[i-1].second+1<=s[i].first-1) t.modify(1,1,dfn[0],s[i-1].second+1,s[i].first-1,p[id].w,type); 93 } 94 s.clear(); 95 } 96 inline int query(const int &x) { 97 return t.query(1,1,dfn[0],dfn[x]); 98 } 99 int main() { 100 const int n=getint(),m=getint(); 101 for(register int i=1;i<n;i++) { 102 add_edge(getint(),getint()); 103 } 104 dfs1(1,0); 105 dfs2(1); 106 for(register int i=1;i<=m;i++) { 107 const int opt=getint(); 108 if(opt==0) { 109 const int u=getint(),v=getint(),w=getint(); 110 p[i]=(Path){u,v,w}; 111 modify(i,1); 112 } 113 if(opt==1) modify(getint(),0); 114 if(opt==2) printf("%d\n",query(getint())); 115 } 116 return 0; 117 }