• 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
    ", 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
    ", ans=-1); 
     87         else printf("%d
    ", 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
  • 相关阅读:
    Http协议的断点续传下载器,使用观察者模式监视下载进度,使用xml保存下载进度。
    C++ 复制到粘贴板
    编译防火墙——C++的Pimpl惯用法解析
    字符串输出
    windows路径操作API函数
    Boost解析xml——xml写入
    智能指针shared_ptr
    Boost 解析xml——插入Item
    ListCtrl添加右键菜单(在对话框类中)
    抓包工具Charles的使用说明
  • 原文地址:https://www.cnblogs.com/mzl0707/p/6341612.html
Copyright © 2020-2023  润新知