您的位置:首页 > 其它

【BZOJ3551】Peaks加强版,主席树+kruskal重构+dfs序+倍增思想

2016-05-05 22:09 302 查看
传送门

写在前面:一道调了不止一上午的题目

思路:我们先来看一下神奇的kruskal重构树



图中红色的是原图的边权,黑色的是原图上的点

这样生成的树有一些十分优美的性质:

1.二叉树(好吧这题意义不大)

2.原树与新树两点间路径上边权(点权)的最大值相等

3.子节点的边权小于等于父亲节点(大根堆)

4.原树中两点之间路径上边权的最大值等于新树上两点的LCA的点权

这些神奇的性质可以解决一些图上的连通性问题。

对于这道题来说,我们就可以kruskal一下(排序+并查集),建出这样一颗二叉树。那么我们每次处理询问的时候,只需要从x一直往权值小于等于要求长度的祖先上蹦,最终所在祖先y的子树就是我们要求的点的范围,即子树上找第k大,这个我们是可以dfs序编号后用主席树来搞一下的。

总结一下就是说,我们先对边权升序排一遍,做成一棵有根的树,然后对这棵树进行dfs重新编号,并离散化原点权(即山的高度),倍增求祖先,然后对dfs后的编号建立主席树。处理询问时我们要一直往上蹦到符合条件的祖先,用主席树寻找第k大即可

注意:

1.这里求得是第k大,也就是第siz-k+1小的数

2.离散化,重编号这里很容易把人搞晕,推荐自己先写写步骤再开始码代码,我这里是先离散化原数据再dfs编号的。

3.倍增预处理和离散化操作在init函数里

4.由于是二叉树,所以采用父亲儿子表示法比较方便

5.题意感觉不是很清晰,这里让求的是第k大的权值……所以还要记录离散化后的数所对应的原权值(ID数组)

代码:

#include<bits/stdc++.h>
#define M 100010
using namespace std;
int n,m,q,lastans,cnt,tot;
int ID[M],belong[M<<1],h[M<<1],fa[M<<1][21],son[M<<1][2],Ls[M<<1],Rs[M<<1];
bool vis[M<<1];
struct Elite
{
int u,v,w;
bool operator <(const Elite other)const
{
return w<other.w;
}
}eli[M*5];
struct Chairman_tree
{
int ch[2],siz;
}a[M*50];
struct node
{
int data,id;
bool operator <(const node other)const
{
return data<other.data;
}
}b[M];
int in()
{
char ch=getchar();int t=0,f=1;
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) t=(t<<3)+(t<<1)+ch-48,ch=getchar();
return f*t;
}
int find(int x)
{
if (x!=belong[x]) belong[x]=find(belong[x]);
return belong[x];
}
void build(int now,int L,int R,int rt,int val)
{
a[rt].siz=a[now].siz+1;
if (L==R) return;
int mid=(L+R)>>1;
if (val<=mid)
a[rt].ch[1]=a[now].ch[1],
a[rt].ch[0]=++cnt,
build(a[now].ch[0],L,mid,a[rt].ch[0],val);
else
a[rt].ch[0]=a[now].ch[0],
a[rt].ch[1]=++cnt,
build(a[now].ch[1],mid+1,R,a[rt].ch[1],val);
}
int get(int begin,int end,int L,int R,int k)
{
if (begin==end) return end;
int mid=(begin+end)>>1,t=a[a[R].ch[0]].siz-a[a[L].ch[0]].siz;
if (k<=t)
return get(begin,mid,a[L].ch[0],a[R].ch[0],k);
else
return get(mid+1,end,a[L].ch[1],a[R].ch[1],k-t);
}
void dfs(int x)
{
vis[x]=1;
if (x<=n) b[++tot].data=h[x],b[tot].id=x;
Ls[x]=tot;
if (son[x][0]) dfs(son[x][0]);
if (son[x][1]) dfs(son[x][1]);
Rs[x]=tot;
}
void init()
{
for (int j=1;j<20;j++)
for (int i=1;i<=cnt;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int i=1;i<=n;i++) b[i].id=i,b[i].data=h[i];
sort(b+1,b+n+1);
for (int i=1;i<=n;i++)
ID[i]=h[b[i].id],h[b[i].id]=i;
}
main()
{
n=in();m=in();q=in();
for (int i=1;i<=n;i++) h[i]=in();
for (int i=1;i<=m;i++)
eli[i].u=in(),eli[i].v=in(),eli[i].w=in();
sort(eli+1,eli+m+1);
cnt=n;
for (int i=1;i<=n<<1;i++) belong[i]=i;
for (int i=1;i<=m;i++)
{
int p=find(eli[i].u),q=find(eli[i].v);
if (p!=q)
fa[p][0]=++cnt,fa[q][0]=cnt,
belong[p]=cnt,belong[q]=cnt,
son[cnt][0]=p,son[cnt][1]=q,
h[cnt]=eli[i].w;
}
fa[cnt][0]=cnt;
init();
for (int i=cnt;i>=1;i--)
if (!vis[i]) dfs(i);
cnt=n+1;
int x,y,z;
for (int i=1;i<=n;i++) build(i,1,n,i+1,b[i].data);
while (q--)
{
if (lastans==-1) lastans=0;
x=in()^lastans;
y=in()^lastans;
z=in()^lastans;
for (int i=19;i>=0;i--)
if (h[fa[x][i]]<=y) x=fa[x][i];
int sz=a[Rs[x]+1].siz-a[Ls[x]+1].siz;
if (sz<z) lastans=-1;
else lastans=ID[get(1,n,Ls[x]+1,Rs[x]+1,sz-z+1)];
printf("%d\n",lastans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: