转载来自于:http://blog.csdn.net/PoPoQQQ/article/details/41348785
弱真不知道这个题解怎么写。
题目大意:同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<sstream> #include<algorithm> #include<vector> #include<bitset> #include<set> #include<queue> #include<stack> #include<map> #include<cstdlib> #include<cmath> #define PI 2*asin(1.0) #define LL long long #define pb push_back #define pa pair<int,int> #define clr(a,b) memset(a,b,sizeof(a)) #define lson lr<<1,l,mid #define rson lr<<1|1,mid+1,r #define bug(x) printf("%d++++++++++++++++++++%d\n",x,x) #define key_value ch[ch[root][1]][0] const int MOD = 1000000007; const int N = 2e5+15; const int maxn = 5e5+1000; const int letter = 130; const int INF = 1e17; const double pi=acos(-1.0); const double eps=1e-8; using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,q,h[N],val[N],father[N],fnp,ps[N]; int tot,head[N],deep[N],fa[N][20],dis[N][20]; int l[N],r[N],top,dfn[N],vis[N],bin[20]; int root[N],ls[N*20],rs[N*20],sum[N*20],siz; struct node{ int x,y,val; bool operator <(const node &a)const{ return val<a.val; } }qu[maxn]; struct edges{ int to,next; }e[N]; int Find(int x){ if(x==father[x]) return x; return father[x]=Find(father[x]); } void init(){ siz=top=tot=0,clr(head,-1); for(int i=1;i<=2*n;i++) father[i]=i; bin[0]=1; for(int i=1;i<=18;i++) bin[i]=bin[i-1]<<1; } int findmax(int x,int val){ for(int i=18;i>=0;i--) if(deep[x]>=bin[i]&&dis[x][i]<=val) x=fa[x][i]; return x; } void addedges(int u,int v){ e[tot].to=v,e[tot].next=head[u],head[u]=tot++; } void dfs(int x){ vis[x]=1; dfn[++top]=x,l[x]=top; for(int i=head[x];i!=-1;i=e[i].next){ int to=e[i].to; deep[to]=deep[x]+1; fa[to][0]=x; dis[to][0]=val[x]; dfs(to); } r[x]=top; } void insert(int l,int r,int x,int &y,int v){ y=++siz; sum[y]=sum[x]+1; if(l==r) return; ls[y]=ls[x],rs[y]=rs[x]; int mid=(l+r)>>1; if(v<=mid) insert(l,mid,ls[x],ls[y],v); else insert(mid+1,r,rs[x],rs[y],v); } int query(int l,int r,int a,int b,int k){ if(l==r) return l; int mid=(l+r)>>1; if(sum[ls[b]]-sum[ls[a]]>=k) return query(l,mid,ls[a],ls[b],k); else return query(mid+1,r,rs[a],rs[b],k-(sum[ls[b]]-sum[ls[a]])); } int main(){ n=read(),m=read(),q=read(); fnp=n;///sum node for(int i=1;i<=n;i++) h[i]=read(),ps[i]=h[i]; sort(ps+1,ps+n+1); for(int i=1;i<=n;i++) h[i]=lower_bound(ps+1,ps+n+1,h[i])-ps; for(int i=0;i<m;i++){ qu[i].x=read(),qu[i].y=read(),qu[i].val=read(); } sort(qu,qu+m); init(); /// kruskal chonggou for(int i=0;i<m;i++){ int xx=Find(qu[i].x),yy=Find(qu[i].y); if(xx!=yy){ fnp++; father[xx]=father[yy]=fnp; addedges(fnp,xx),addedges(fnp,yy); val[fnp]=qu[i].val; } }/// kruskal tree for(int i=1;i<=n;i++){ if(!vis[i]) dfs(Find(i)); } for(int j=1;j<=18;j++) for(int i=1;i<=fnp;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]); } for(int i=1;i<=top;i++){ ///dfs xu int x=dfn[i]; if(x<=n) insert(1,n,root[i-1],root[i],h[x]); else root[i]=root[i-1]; } int ans=-1; while(q--){ int x,v,k,aim; x=read(),v=read(),k=read(); if(ans!=-1) x=x^ans,v=v^ans,k=k^ans; aim=findmax(x,v);/// root int la=root[l[aim]],ra=root[r[aim]]; if(sum[ra]-sum[la]<k) ans=-1; else ans=query(1,n,la,ra,sum[ra]-sum[la]+1-k),ans=ps[ans]; printf("%d\n",ans); } return 0; }