zoukankan      html  css  js  c++  java
  • soj97 旅行

    题意:给你一棵n个点的树。m个操作,op 1:在点i上建立银行。op 2:询问从点x开始可以经过至少一个银行走到的点中编号第二大的点。

    n,m<=1e5.

    标程:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5     int x=0;char ch=getchar();
     6     while (ch<'0'||ch>'9') ch=getchar();
     7     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
     8     return x;
     9 }
    10 const int N=100005;
    11 set<int,greater<int> > s;
    12 set<int,greater<int> >::iterator it;
    13 int cnt,head[N],Mx[N],Mxc[N],f[N],tot,ans[N],tag[N],u,v,n,m;
    14 struct node{int to,next;}num[N*2];
    15 struct _node{int op,x;}q[N];
    16 void add(int x,int y)
    17 {num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;}
    18 int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
    19 void merge(int x,int y)
    20 {
    21     if (x==y) return;
    22     s.erase(Mx[x]);s.erase(Mx[y]);
    23     s.erase(Mxc[x]);s.erase(Mxc[y]);
    24     if (Mx[x]>Mx[y]) Mxc[y]=Mx[y],Mx[y]=Mx[x];//注意最大次大的传递 
    25     else if (Mx[x]>Mxc[y]) Mxc[y]=Mx[x];
    26     if (Mxc[x]>Mxc[y]) Mxc[y]=Mxc[x]; 
    27     s.insert(Mx[y]);s.insert(Mxc[y]);
    28     f[x]=y;
    29 }
    30 void dfs(int x,int fa)
    31 {
    32     if (tag[x]) s.insert(x);//银行作为单点也要加入 
    33     for (int i=head[x];i;i=num[i].next)
    34       if (num[i].to!=fa)
    35       {
    36            dfs(num[i].to,x);
    37            if (!tag[num[i].to]&&!tag[x]) merge(find(num[i].to),find(x));
    38       }
    39 }
    40 int qry(int x)
    41 {
    42     int fl=0;x=find(x);
    43     for (it=s.begin();it!=s.end();++it)
    44     {
    45         if (*it==Mx[x]||*it==Mxc[x]) continue;
    46         if (!fl) fl=1;else return *it;
    47     }
    48     return -1;
    49 }
    50 int main()
    51 {
    52     n=read();m=read();tot=0;s.clear();
    53     memset(head,0,sizeof(head));cnt=0;
    54     for (int i=1;i<n;i++) u=read(),v=read(),add(v,u),add(u,v);
    55     for (int i=1;i<=n;i++) f[i]=i,Mx[i]=i,Mxc[i]=0,s.insert(i);
    56     for (int i=1;i<=m;i++) 
    57     {
    58        q[i].op=read(),q[i].x=read();
    59        if (q[i].op==1) tag[q[i].x]++;//有可能被该银行被统计多次 
    60     }
    61     dfs(1,-1);
    62     for (int i=m;i>=1;i--)
    63     {
    64        if (q[i].op==1) 
    65        {
    66           int now=find(q[i].x);tag[q[i].x]--;
    67           if (!tag[q[i].x]) 
    68             for (int j=head[q[i].x];j;j=num[j].next)
    69               if (!tag[num[j].to]) merge(find(num[j].to),now);
    70        }else ans[++tot]=qry(q[i].x);
    71     }
    72     while (tot) printf("%d
    ",ans[tot--]);
    73     return 0;
    74 }

    题解:并查集+技巧

    暴力可以过很多啊,倒着枚举编号点,判断x和该编号点的路径上是否有银行,树链剖分+线段树(lct)维护即可。

    因为连通块拆分比较麻烦,考虑倒着执行操作,相当于删去银行。每删去一个银行就相当于把若干个连通块合并。

    询问即是问除了x点所在连通块其他部分的第二大。维护一个保存每个连通块最大次大的set,取出不等于当前连通块最大次大的第二大元素,最多取4次即可。

    时间复杂度O((n+m)(logn+a(n))。

  • 相关阅读:
    securefile allocation chunks
    脚本:Segment Space Usage Explorer
    Script:10g中不用EM显示Active Session Count by Wait Class
    理解IMPDP ORA19505、ORA31640错误
    了解ocssd.bin如何控制RAC节点重启
    Oracle等待事件:NULL EVENT
    LGWR TRACE Warning: log write time
    MySql隔离级别多线程并发读取数据时的正确性
    Oracle事务处理—隔离级别
    Oracle函数详解
  • 原文地址:https://www.cnblogs.com/Scx117/p/8933328.html
Copyright © 2011-2022 走看看