bzoj3545 && bzoj3551 Peaks(离线版&&在线版)

题目给n点m边的无向图,有点权和边权

每次询问求点v在经过路径上的边都不超过w的情况下,能到达的第k大的点的权值

首先离线版比较容易想到,属于我现在能码出来的最难的码农题之一吧T T

这道题思路是这样的

1、对于边权的限制条件,可以先想到做一棵最小生成树

2、对于第k大这种询问,可以建权值线段树,但是山的高度太大到1e9,所以我们还要先离散化到1e6的水平才能用线段树

3、显然不能对每个询问w都建线段树,因此要用到主席树。具体做法是将询问和边权都排序(详情看代码),给每个点建一棵线段树,然后边建mst边回答询问,每次合并两个连通块的时候,要将两个连通块的线段树合并起来,线段树支持区间加减的优势就出来了

离线的做法是这样的,代码也挺好写

然后再来考虑在线怎么做= =

题解的做法很神,很难想到

同样是建最小生成树,不过做了变形

比如每次连边有 x=find(e[i].from), y=find(e[i].to);

这时候新建一个节点z,点权是边权

然后fa[x]=fa[y]=z,即新建的节点是此连通块的根

这样做有什么用呢。。好处就是建完树后,所有的MST的节点都在叶子节点,上边的全是由边转化的点

而且由kruskal的过程可知,越晚加入的边,边权越大,因此在新树中,除了叶子节点,越往上点的权值越大

这一点就可以被每次询问的边权不超过w所用,此时w只要从询问的v开始,倍增往上找到第一个边权大于它的点

一开始还要求出此树的dfs序:叶子节点仅保留一次,非叶子节点(即边的节点)保留low和high

然后建主席树,仅叶子节点要修改权值线段树,否则不进行修改,将上棵树的根复制过来

询问的时候,找到第一个大于w的点v,利用low[v]和high[v]这两个根的线段树,减一减就是v在不超过w的情况下能走到的点的权值

然后找就是了

离线:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn = 100002;
 6 struct node{
 7     int u,v,w,id;
 8     bool q;
 9 }e[maxn*10];
10 int n,m,T,N,ls[maxn*50],rs[maxn*50],sum[maxn*50],tot,h[maxn],ori[maxn],a[maxn],root[maxn],fa[maxn],ans[maxn*5];
11 
12 void read(int &x){
13     x=0; int f=1; char c=getchar();
14     while (c<'0' || c>'9'){if (c=='-') f=-1; c=getchar();}
15     while (c>='0' && c<='9') x=x*10+c-48,c=getchar();
16     x*=f;
17 }
18 
19 bool operator<(node a, node b){
20     return a.w==b.w?a.q<b.q:a.w<b.w;
21 }
22 
23 int find(int x){
24     return fa[x]==x?x:fa[x]=find(fa[x]);
25 }
26 
27 void insert(int &x, int l, int r, int pos){
28     if (!x) x=++tot;
29     if (l==r){
30         sum[x]=1;
31         return;
32     }
33     int mid=l+r>>1;
34     if (pos<=mid) insert(ls[x],l,mid,pos);
35     else insert(rs[x],mid+1,r,pos);
36     sum[x]=sum[ls[x]]+sum[rs[x]];
37 }
38 
39 int merge(int x, int y){
40     if (!x || !y) return x+y;
41     if (!ls[x] && !rs[x]){
42         sum[x]+=sum[y];
43         return x;
44     }
45     ls[x]=merge(ls[x],ls[y]);
46     rs[x]=merge(rs[x],rs[y]);
47     sum[x]=sum[ls[x]]+sum[rs[x]];
48     return x;
49 }
50 
51 int query(int x, int l, int r, int pos){
52     if (l==r) return l; int mid=l+r>>1;
53     if (sum[ls[x]]>=pos) return query(ls[x],l,mid,pos);
54     else return query(rs[x],mid+1,r,pos-sum[ls[x]]);
55 }
56 
57 int main(){
58     read(n); read(m); read(T);
59     for (int i=1; i<=n; i++) read(h[i]), a[i]=h[i];
60     sort(a+1,a+1+n); N=unique(a+1,a+1+n)-a-1;
61     for (int i=1,height; i<=n; i++) height=h[i],h[i]=lower_bound(a+1,a+1+N,h[i])-a,ori[h[i]]=height;
62     for (int i=1; i<=n; i++) insert(root[i],1,n,h[i]),fa[i]=i;
63     for (int i=1; i<=m; i++) read(e[i].u), read(e[i].v), read(e[i].w), e[i].q=0;
64     for (int i=1+m; i<=T+m; i++) read(e[i].u), read(e[i].w), read(e[i].v), e[i].q=1, e[i].id=i-m;
65     sort(e+1,e+1+m+T);
66     for (int i=1,cnt=0,u,v; i<=m+T; i++){
67         if (!e[i].q){
68             if (cnt==n-1) continue;
69             u=find(e[i].u), v=find(e[i].v);
70             if (u!=v){
71                 fa[u]=v; cnt++;
72                 root[v]=merge(root[u],root[v]);
73             }
74         }
75         else{
76             int x=find(e[i].u);
77             if (sum[root[x]]<e[i].v) ans[e[i].id]=-1;
78             else ans[e[i].id]=ori[query(root[x],1,n,sum[root[x]]-e[i].v+1)];
79         }
80     }
81     for (int i=1; i<=T; i++) printf("%d\n", ans[i]);
82     return 0;
83 }
View Code

在线:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 using namespace std;
  5 const int logn = 17, maxn = 200005;
  6 struct node{
  7     int to,next;
  8 }e[maxn];
  9 struct data{
 10     int u,v,w;
 11 }E[maxn*3];
 12 int n,m,T,tot,cnt,ans,head[maxn],f[maxn],fa[maxn][logn+1],dep[maxn],mx[maxn][logn+1];
 13 int N,h[maxn],orz[maxn],a[maxn],top,low[maxn],high[maxn],root[maxn*2],st[maxn*2];
 14 int ls[5000005],rs[5000005],sum[5000005];
 15 
 16 void read(int &x){
 17     x=0; char c=getchar(); int f=1;
 18     while (c<'0' || c>'9'){if (c=='-') f=-1; c=getchar();}
 19     while (c>='0' && c<='9') x=x*10+c-48, c=getchar();
 20     x*=f;
 21 }
 22 bool operator<(data a, data b){return a.w<b.w;}
 23 void insert(int u, int v){e[++tot].to=v; e[tot].next=head[u]; head[u]=tot;}
 24 int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
 25 
 26 int getrt(int u, int val){
 27     for (int i=logn; i>=0; i--)
 28         if (dep[u]>(1<<i) && mx[u][i]<=val) u=fa[u][i];
 29     return u;
 30 }
 31 
 32 void dfs(int u){
 33     st[++top]=u; dep[u]=dep[fa[u][0]]+1;
 34     if (u>n) low[u]=top;
 35     for (int i=1; i<=logn; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
 36     for (int i=1; i<=logn; i++) mx[u][i]=max(mx[u][i-1],mx[fa[u][i-1]][i-1]);
 37     for (int i=head[u],v; i; i=e[i].next) fa[v=e[i].to][0]=u,mx[v][0]=h[u],dfs(v);
 38     if (u>n) st[++top]=u,high[u]=top;
 39 }
 40 
 41 void update(int &x, int l, int r, int last, int pos){
 42     x=++cnt;  //注意这里千万不要if(!x) 
 43     sum[x]=sum[last]+1;
 44     if (l==r) return; else ls[x]=ls[last],rs[x]=rs[last];
 45     int mid=l+r>>1;
 46     if (pos<=mid) update(ls[x],l,mid,ls[last],pos);
 47     else update(rs[x],mid+1,r,rs[last],pos);
 48 }
 49 
 50 int query(int l, int r, int x, int y, int rk){
 51     if (l==r) return l;
 52     int mid=l+r>>1,s=sum[ls[y]]-sum[ls[x]];  //注意是  左子树的sum差 
 53     if (s>=rk) return query(l,mid,ls[x],ls[y],rk);
 54     else return query(mid+1,r,rs[x],rs[y],rk-s);
 55 }
 56 
 57 void build(){
 58     for (int i=1; i<=m; i++) read(E[i].u),read(E[i].v),read(E[i].w);
 59     sort(E+1,E+1+m);
 60     N=n; tot=1; cnt=0;
 61     for (int i=1; i<=2*n; i++) f[i]=i;
 62     for (int i=1,tmp; i<=m; i++){
 63         int u=find(E[i].u), v=find(E[i].v);
 64         if (u!=v){
 65             tmp=++N;
 66             f[u]=f[v]=tmp; h[tmp]=E[i].w;
 67             insert(tmp,v); insert(tmp,u);
 68             if (N==2*n-1) break;
 69         }
 70     }
 71     for (int i=1; i<=n; i++) if (!dep[i]) dfs(find(i));
 72     for (int i=1,x; i<=top; i++){
 73         x=st[i]; 
 74         if (x<=n) update(root[i],1,n,root[i-1],h[x]);
 75         else root[i]=root[i-1];
 76     }
 77 }
 78 
 79 void solve(){
 80     while (T--){
 81         int v,x,k,t,a,b,tot;
 82         read(v); read(x); read(k);
 83         if (ans!=-1) v^=ans,x^=ans,k^=ans;
 84         t=getrt(v,x);
 85         a=low[t]; b=high[t]; 
 86         if ((tot=sum[root[b]]-sum[root[a]])<k) printf("%d\n", ans=-1); 
 87         else printf("%d\n", ans=orz[query(1,n,root[a],root[b],tot-k+1)]);
 88     }
 89 }
 90 
 91 void pre(){
 92     read(n); read(m); read(T);
 93     for (int i=1; i<=n; i++) read(h[i]),a[i]=h[i];
 94     sort(a+1,a+1+n); N=unique(a+1,a+1+n)-a-1;
 95     for (int i=1,height; i<=n; i++) height=h[i],h[i]=lower_bound(a+1,a+1+N,h[i])-a,orz[h[i]]=height;
 96 }
 97 
 98 int main(){
 99     pre();
100     build();
101     solve();
102     return 0;
103 }
View Code

 

posted @ 2017-01-22 23:01  mzl0707  阅读(601)  评论(0编辑  收藏  举报