BZOJ3551 [ONTAK2010]Peaks加强版

题目链接:戳我

woc这题也太毒了吧。。。。卡空间要死啊???
说一说怎么做——因为本题强制在线,所以用kruskal重构树,开始将边权从小到大排序,这样的话用最后一个新建的节点为根之后就是一个大根堆,所有边权小的都在节点的子树里。求K大——主席树。不过因为我们维护的是一棵树而不是序列,所以还要先dfs序一下。

可惜蒟蒻码力不够,虽然看出来了怎么写但是还是不断锅锅锅,最后还是去参照了大佬的题解才过的这个题。。。。。

bzoj上题面不是特别清楚。在这里补充一下——
v=v xor lastans,x=x xor lastans,k=k xor lastans。如果lastans=-1则不变。
这句话的意思是lastans是上一次询问的答案,如果上一次ans==-1,就不对v,x,k进行异或操作。开始lastans=0。
然后题目让求的是第K大而非第K小(因为中国汉字意义博大精深,我看到第几大总是习惯性的先从小的想。。。。。告辞

补一下正确的样例输入输出:
输入:
10 11 4

1 2 3 4 5 6 7 8 9 10

1 4 4

2 5 3

9 8 2

7 8 10

7 1 4

6 7 1

6 4 8

2 1 5

10 8 10

3 4 7

3 4 6

1 5 2

1 5 6

1 5 8

8 9 2
输出:
6
10
9
-1

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define MAXN 200100
using namespace std;
int n,m,tot,edge_number,cnt,tt,num,lastans,q,kkk;
int pre[MAXN],h[MAXN],head[MAXN],fa[MAXN],dis[MAXN];
int ini[MAXN],rt[MAXN],dfn[MAXN],low[MAXN],f[MAXN][20];
struct Edge{int nxt,to;}edge[MAXN<<1];
struct Edge2{int u,v,w;}e[MAXN<<2];
struct Node{int ls,rs,v;}t[MAXN<<5];
inline void add(int from,int to)
{
    edge[++edge_number].nxt=head[from];
    edge[edge_number].to=to;
    head[from]=edge_number;
}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline bool cmp(struct Edge2 x,struct Edge2 y){return x.w<y.w;}
inline void dfs(int now,int ff)
{
    //printf("now=%d ff=%d\n",now,ff);
    if(now<=n) dfn[now]=low[now]=++tt,ini[tt]=now;
    else dfn[now]=(int)1e9,low[now]=0;
    f[now][0]=ff;
    for(int i=1;i<=19;i++)
        f[now][i]=f[f[now][i-1]][i-1];
    for(int i=head[now];i;i=edge[i].nxt)
    {
        dfs(edge[i].to,now);
        dfn[now]=min(dfn[now],dfn[edge[i].to]);
        low[now]=max(low[now],low[edge[i].to]);
    }
}
inline void modify(int &now,int ff,int l,int r,int pos)
{
    now=++kkk;
    t[now]=t[ff],t[now].v++;
    //printf("now=%d ff=%d l=%d r=%d pos=%d\n",now,ff,l,r,pos);
    if(l==r) return;
    int mid=(l+r)>>1;
    if(pos<=mid) modify(t[now].ls,t[ff].ls,l,mid,pos);
    else modify(t[now].rs,t[ff].rs,mid+1,r,pos);
}
inline int query(int now,int ff,int l,int r,int k)
{
    if(l==r) return pre[l];
    int mid=(l+r)>>1;
    int cur_ans=t[t[ff].rs].v-t[t[now].rs].v;
    if(cur_ans>=k) query(t[now].rs,t[ff].rs,mid+1,r,k);
    else query(t[now].ls,t[ff].ls,l,mid,k-cur_ans);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin); 
    //freopen("ce.out","w",stdout);
    #endif
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++) 
        scanf("%d",&h[i]),pre[i]=h[i];
    sort(&pre[1],&pre[1+n]);
    cnt=unique(&pre[1],&pre[1+n])-pre-1;
    for(int i=1;i<=n;i++)
        h[i]=lower_bound(&pre[1],&pre[1+cnt],h[i])-pre;
    for(int i=1;i<=n;i++) 
        fa[i]=i;
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    sort(&e[1],&e[1+m],cmp);
    tot=n;
    for(int i=1;i<=m;i++)
    {
        int a=find(e[i].u),b=find(e[i].v);
        if(a==b) continue;
        ++tot;
        fa[tot]=fa[a]=fa[b]=tot;
        dis[tot]=e[i].w;
        add(tot,a),add(tot,b);
    }
    dfs(tot,0);
    for(int i=1;i<=n;i++)
        modify(rt[i],rt[i-1],1,cnt,h[ini[i]]);
    //for(int i=1;i<=n;i++) printf("rt[%d]=%d\n",i,rt[i]);
    for(int i=1;i<=q;i++)
    {
        int v,x,k;
        scanf("%d%d%d",&v,&x,&k);
        if(lastans!=-1) v^=lastans,x^=lastans,k^=lastans;
        for(int i=19;i>=0;i--)
            if(f[v][i]&&dis[f[v][i]]<=x)
                v=f[v][i];
        //printf("%d %d\n",rt[dfn[v]-1],rt[low[v]]);
        if(low[v]-dfn[v]+1<k) lastans=-1;
        else lastans=query(rt[dfn[v]-1],rt[low[v]],1,cnt,k);
        printf("%d\n",lastans);
    }
    return 0;   
}

不过有个问题是 从BZOJ上捞下来的数据为什么我自己在lemon上测是RE+TLE 放到BZOJ上竟然又跑过了????
update:没开栈。。开了就过了

posted @ 2019-01-25 19:12  风浔凌  阅读(134)  评论(0编辑  收藏  举报