bzoj4538: [Hnoi2016]网络
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4538
思路:首先二分答案K
那么对于每个询问我们只要判断权值大于K的路径的交是否都过x即可
路径的交还是路径,路径交满足结合律
可以离线拿个线段树维护一下即可,以权值为关键字,每个点记录该段区间的路径交
也可以用splay来做
二分时在线段树上二分即可。
如果lca用倍增求,复杂度是O(nlog^2n)
链交好像写的比较丑.....又是一波讨论
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> const int maxn=200010,maxm=200010,maxk=22; using namespace std; struct quer{int op,t,x,pos;}q[maxn]; int n,m,pw[maxk],lg[300010],cnt,dep[maxn],tot; struct Tgraph{ int pre[maxm],now[maxn],son[maxm],tot,fa[maxn][maxk],dfn[maxn],last[maxn],tim; void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;} void ins(int a,int b){add(a,b),add(b,a);} void dfs(int x){ dfn[x]=++tim; for (int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0]) fa[son[y]][0]=x,dep[son[y]]=dep[x]+1,dfs(son[y]); last[x]=tim; } int lca(int x,int y){ if (dep[x]<dep[y]) swap(x,y); for (int i=0,h=dep[x]-dep[y];h;i++) if (pw[i]&h) h-=pw[i],x=fa[x][i]; if (x==y) return x; for (int i=lg[dep[x]];i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } inline bool in(int x,int y){return dfn[x]>=dfn[y]&&dfn[x]<=last[y];}//判断x是否在y的子树里 }g; struct chain{ int u,v,lca; bool in(int x){//判断x是否在链上 if (!lca) return 1; if (lca>0) return g.in(x,lca)&&(g.in(u,x)||g.in(v,x)); return 0; } void print(){printf("u=%d v=%d lca=%d\n",u,v,lca);} }; struct data{ chain ch;int id,v; void init(int i){scanf("%d%d%d",&ch.u,&ch.v,&v),ch.lca=g.lca(ch.u,ch.v),id=i;} void print(){ch.print(),printf("id=%d val=%d\n",id,v);} }seq[maxn]; bool cmp(data a,data b){return a.v<b.v;} chain merge(chain a,chain b){ if (!a.lca) return b;//0是这个路径已被删去,-1是交集为空 if (!b.lca) return a; if (a.lca==-1||b.lca==-1) return (chain){0,0,-1}; if (dep[a.lca]<dep[b.lca]) swap(a,b); if (!b.in(a.lca)) return (chain){0,0,-1}; int lcau=g.lca(a.u,b.u),lcav=g.lca(a.v,b.v); int newu=dep[lcau]>dep[a.lca]?lcau:a.lca; int newv=dep[lcav]>dep[a.lca]?lcav:a.lca; return (chain){newu,newv,a.lca}; } struct Tsegment{ #define ls (p<<1) #define rs (p<<1|1) #define mid ((l+r)>>1) chain t[maxn<<2]; void update(int p){t[p]=merge(t[ls],t[rs]);} void modify(int p,int l,int r,int x,chain ch){ if (l==r){t[p]=ch;return;} if (x<=mid) modify(ls,l,mid,x,ch); else modify(rs,mid+1,r,x,ch); update(p); } int query(int p,int l,int r,int x){ if (l==r) return seq[l].v; if (t[rs].in(x)) return query(ls,l,mid,x); else return query(rs,mid+1,r,x); } }T; int query(int x){ if (!tot) return -1; chain ch=T.t[1]; if (ch.in(x)) return -1; return T.query(1,1,cnt,x); } int main(){ scanf("%d%d",&n,&m),pw[0]=1,lg[1]=0; for (int i=1;i<=18;i++){ pw[i]=pw[i-1]<<1; for (int j=pw[i-1]+1;j<=pw[i];j++) lg[j]=i; } for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),g.ins(x,y); g.dfs(1); for (int i=1;i<=m;i++){ scanf("%d",&q[i].op); if (q[i].op==0) seq[++cnt].init(i); else if (q[i].op==1) scanf("%d",&q[i].t); else scanf("%d",&q[i].x); } sort(seq+1,seq+1+cnt,cmp); for (int i=1;i<=cnt;i++) q[seq[i].id].pos=i; for (int i=1;i<=m;i++){ if (q[i].op==0) T.modify(1,1,cnt,q[i].pos,seq[q[i].pos].ch),tot++; else if (q[i].op==1) T.modify(1,1,cnt,q[q[i].t].pos,(chain){0,0,0}),tot--; else printf("%d\n",query(q[i].x)); } return 0; }