BZOJ3545: [ONTAK2010]Peaks

n<=100000,m<=500000的图有点权边权,q<=500000个询问每次问从x出发经过不超过y的边权能到的点权第K大,加强版强制在线。

Emmmmmm有一个漂亮的方法来转化,就是对原图做MST,做的时候要连接两个点时不要直接连,新开一个点然后让这两个点连上这个点。

这样就把边权挂到树上了,新建的点的点权代表对应的边权,由于是从小到大加边,建成的树上下面的“新建点”的点权一定小于上面的“新建点”的点权,每次回答询问在树上倍增找到点权不超过y的祖先,然后就查询这个祖先的子树内的叶子点的第K大,dfs序+主席树即可。

然后有个小问题,图不一定联通。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<stdlib.h>
  5 //#include<iostream>
  6 using namespace std;
  7 
  8 int n,m,q;
  9 #define maxn 200011
 10 #define maxm 2000011
 11 struct Point
 12 {
 13     int from,to,v;
 14     bool operator < (const Point &b) const {return v<b.v;}
 15 }p[maxm];
 16 
 17 int ufs[maxn];
 18 void ufsclear(int n) {for (int i=1;i<=n;i++) ufs[i]=i;}
 19 int find(int x) {return x==ufs[x]?x:(ufs[x]=find(ufs[x]));}
 20 void Union(int x,int y) {x=find(x),y=find(y);if (x==y) return;ufs[x]=y;}
 21 struct SMT
 22 {
 23     struct Node
 24     {
 25         int son[2];
 26         int cnt;
 27     }a[maxm];
 28     int size,n;
 29     void clear(int m) {n=m;size=0;a[0].cnt=0;}
 30     void insert(int pre,int &rt,int L,int R,int num)
 31     {
 32         rt=++size;
 33         a[rt].cnt=a[pre].cnt+1;
 34         if (L==R) {a[rt].son[0]=a[rt].son[1]=0;return;}
 35         const int mid=(L+R)>>1;
 36         if (num<=mid) insert(a[pre].son[0],a[rt].son[0],L,mid,num),a[rt].son[1]=a[pre].son[1];
 37         else insert(a[pre].son[1],a[rt].son[1],mid+1,R,num),a[rt].son[0]=a[pre].son[0];
 38     }
 39     void insert(int pre,int &rt,int num) {insert(pre,rt,1,n,num);}
 40 }smt;
 41 
 42 struct Edge{int to,next;}edge[maxn<<1];int first[maxn],le=2;
 43 void in(int x,int y) {Edge &e=edge[le];e.to=y;e.next=first[x];first[x]=le++;}
 44 
 45 int val[maxn],fa[maxn][20],lisan[maxn],li=0,dep[maxn],ll[maxn],list[maxn],rr[maxn],Time=0;
 46 void dfs(int x)
 47 {
 48     ll[x]=Time+1;
 49     for (int i=first[x];i;i=edge[i].next)
 50     {
 51         const Edge &e=edge[i];
 52         dep[e.to]=dep[x]+1;
 53         dfs(e.to);
 54     }
 55     if (!first[x]) list[++Time]=x;
 56     rr[x]=Time;
 57 }
 58 
 59 int lca(int x,int y)
 60 {
 61     if (dep[x]<dep[y]) {int t=x;x=y;y=t;}
 62     for (int i=18;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
 63     if (x==y) return x;
 64     for (int i=18;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
 65     return fa[x][0];
 66 }
 67 
 68 int rt[maxn];
 69 int main()
 70 {
 71     scanf("%d%d%d",&n,&m,&q);
 72     for (int i=1;i<=n;i++) scanf("%d",&val[i]),lisan[++li]=val[i];
 73     sort(lisan+1,lisan+1+n);li=unique(lisan+1,lisan+1+li)-lisan-1;
 74     for (int i=1;i<=n;i++) val[i]=lower_bound(lisan+1,lisan+1+li,val[i])-lisan;
 75     
 76     for (int i=1;i<=m;i++) scanf("%d%d%d",&p[i].from,&p[i].to,&p[i].v);
 77     sort(p+1,p+1+m);
 78     ufsclear(n+n);
 79     for (int i=1,cnt=1;i<=m;i++)
 80     {
 81         int x=find(p[i].from),y=find(p[i].to);
 82         if (x==y) continue;
 83         int now=n+cnt; val[now]=p[i].v;
 84         Union(x,now); Union(y,now);
 85         in(now,x); in(now,y);
 86         fa[x][0]=now;fa[y][0]=now;
 87         cnt++; if (cnt==n) break;
 88     }
 89     int tot=n+n-1;
 90     for (int j=1;j<=18;j++)
 91         for (int i=1;i<=tot;i++)
 92             fa[i][j]=fa[fa[i][j-1]][j-1];
 93     dep[tot]=1;
 94     for (int i=1;i<=tot;i++) if (!fa[i][0]) dfs(i);
 95     
 96     smt.clear(li);
 97     for (int i=1;i<=n;i++) smt.insert(rt[list[i-1]],rt[list[i]],val[list[i]]);
 98     int last=-1;
 99     for (int i=1,x,y,K;i<=q;i++)
100     {
101         scanf("%d%d%d",&x,&y,&K);
102         if (last>=0) x^=last,y^=last,K^=last;
103         int num=val[x],t=x;
104         for (int j=18;j>=0;j--) if (fa[t][j] && val[fa[t][j]]<=y) t=fa[t][j];
105 //        cout<<t<<endl;
106         int u=rt[list[ll[t]-1]],v=rt[list[rr[t]]],L=1,R=li,tmp;
107         if (smt.a[v].cnt-smt.a[u].cnt<K) {printf("%d\n",(last=-1));continue;}
108         while (L<R)
109         {
110             const int mid=(L+R)>>1;
111             if ((tmp=smt.a[smt.a[v].son[1]].cnt-smt.a[smt.a[u].son[1]].cnt)>=K)
112                 v=smt.a[v].son[1],u=smt.a[u].son[1],L=mid+1;
113             else v=smt.a[v].son[0],u=smt.a[u].son[0],K-=tmp,R=mid;
114         }
115         printf("%d\n",(last=lisan[L]));
116     }
117     return 0;
118 }
View Code

 

转载于:https://www.cnblogs.com/Blue233333/p/7944161.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值