题目大意:同3545 强制在线
3545题解传送门:http://blog.csdn.net/popoqqq/article/details/40660953
强制在线没法排序 启发式合并也就用不了了
Kruskal重构树是个挺好玩的东西 可以拿来处理一些最小生成树的边权最值问题
这里我们Kruskal连边时并不直接连边 而是新建一个节点ext 将两个点所在子树都连到ext的儿子上
比如说样例的树就建成了这样
图中红色的是原图的边权,黑色的是原图上的点
这样生成的树有一些十分优美的性质:
1.二叉树(好吧这题意义不大)
2.原树与新树两点间路径上边权(点权)的最大值相等
3.子节点的边权小于等于父亲节点(大根堆)
4.原树中两点之间路径上边权的最大值等于新树上两点的LCA的点权
于是对于每个询问 我们从这个询问向上倍增寻找深度最小的点权小于等于x的点 易证这个节点的子树就是v所能到达的所有点
DFS序+可持久化线段树直接搞就行
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 200200 using namespace std; struct Segtree{ Segtree *ls,*rs; int num; void* operator new (size_t size,Segtree *_,Segtree *__,int ___); }*tree[M],*mempool,*C; struct edge{ int x,y,f; bool operator < (const edge &Y) const { return f < Y.f ; } }edges[500500]; struct abcd{ int to,next; }table[M]; int head[M],tot; int n,m,q,ans; int a[M],fa[M][20],dis[M][20],belong[M]; int seq[M],l[M],r[M],cnt; void* Segtree :: operator new (size_t size,Segtree *_,Segtree *__,int ___) { if(C==mempool) { C=new Segtree[1<<15]; mempool=C+(1<<15); } C->ls=_; C->rs=__; C->num=___; return C++; } void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } int Find(int x) { if(!belong[x]||belong[x]==x) return belong[x]=x; return belong[x]=Find(belong[x]); } void Kruskal() { int i; sort(edges+1,edges+m+1); for(i=1;i<=m;i++) { int x=Find(edges[i].x); int y=Find(edges[i].y); if(x==y) continue; belong[x]=belong[y]=++n; fa[x][0]=fa[y][0]=n; dis[x][0]=dis[y][0]=edges[i].f; Add(n,x);Add(n,y); } } void DFS(int x) { int i; seq[l[x]=++cnt]=a[x]; for(i=head[x];i;i=table[i].next) DFS(table[i].to); r[x]=cnt; } Segtree* Build_Tree(Segtree *p,int x,int y,int val) { int mid=x+y>>1; if(x==y) return new (0x0,0x0,p->num+1) Segtree; if(val<=mid) return new (Build_Tree(p->ls,x,mid,val),p->rs,p->num+1) Segtree; else return new (p->ls,Build_Tree(p->rs,mid+1,y,val),p->num+1) Segtree; } int Get_Kth(Segtree *p1,Segtree *p2,int x,int y,int k) { int mid=x+y>>1; if(x==y) return mid; int temp=p2->rs->num-p1->rs->num; if(k<=temp) return Get_Kth(p1->rs,p2->rs,mid+1,y,k); else return Get_Kth(p1->ls,p2->ls,x,mid,k-temp); } int Get_Root(int x,int y) { int j; for(j=19;~j;j--) if( fa[x][j] && dis[x][j]<=y ) x=fa[x][j]; return x; } int main() { int i,j,v,x,k; cin>>n>>m>>q; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f); Kruskal(); for(j=1;j<=19;j++) for(i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1], dis[i][j]=max(dis[i][j-1],dis[fa[i][j-1]][j-1]); DFS(n); tree[0]=new (0x0,0x0,0) Segtree; tree[0]->ls=tree[0]->rs=tree[0]; for(i=1;i<=n;i++) tree[i]=Build_Tree(tree[i-1],0,1000000000,seq[i]); for(i=1;i<=q;i++) { scanf("%d%d%d",&v,&x,&k); x^=ans;v^=ans;k^=ans; int root=Get_Root(v,x); if(r[root]-l[root]+1<k) { puts("-1"); ans=0; continue; } ans=Get_Kth(tree[l[root]-1],tree[r[root]],0,1000000000,k); if(!ans) { puts("-1"); continue; } printf("%d\n",ans); } }