zoukankan      html  css  js  c++  java
  • bzoj 3991 寻宝游戏

    题目大意:

    一颗树 有一个点的集合

    对于每个集合的答案为 从集合内一个点遍历集合内所有点再返回的距离最小值

    每次可以选择一个点 若在集合外便加入集合 若在集合内就删除

    求每次操作后这个集合的答案

    思路:

    对于每个集合 

    它的答案一定为从dfs序最小的开始依次遍历再回来

    当加入一个点x的时候 可以找到它dfs序的前驱与后继 画图可得 ans+=dis(pre,x)+dis(x,sub)-dis(pre,sub)  删除的时候为ans-=

    特别地 当x没有前驱或后继时 前驱为最大值 后继为最小值(当做一个环

    因此我们维护一颗平衡树搞一下即可

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cmath>
      4 #include<cstdlib>
      5 #include<cstring>
      6 #include<algorithm>
      7 #include<vector>
      8 #include<queue>
      9 #include<set>
     10 #define inf 2139062143
     11 #define ll long long
     12 #define MAXN 100100
     13 using namespace std;
     14 inline int read()
     15 {
     16     int x=0,f=1;char ch=getchar();
     17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
     18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
     19     return x*f;
     20 }
     21 int ch[MAXN][2],fa[MAXN],sz,cnt[MAXN],val[MAXN],size[MAXN],rt;
     22 int which(int x) {return x==ch[fa[x]][1];}
     23 int find_pre()
     24 {
     25     int pos=ch[rt][0];
     26     while(ch[pos][1]) pos=ch[pos][1];
     27     return pos;
     28 }
     29 int find_max()
     30 {
     31     int pos=ch[rt][1];
     32     while(ch[pos][1]) pos=ch[pos][1];
     33     return pos;
     34 }
     35 int find_min()
     36 {
     37     int pos=ch[rt][0];
     38     while(ch[pos][0]) pos=ch[pos][0];
     39     return pos;
     40 }
     41 int find_sub()
     42 {
     43     int pos=ch[rt][1];
     44     while(ch[pos][0]) pos=ch[pos][0];
     45     return pos;
     46 }
     47 void upd(int x)
     48 {
     49     if(!x) return ;
     50     size[x]=cnt[x]+size[ch[x][1]]+size[ch[x][0]];
     51 }
     52 void rotate(int pos)
     53 {
     54     int f=fa[pos],ff=fa[f],k=which(pos);
     55     ch[f][k]=ch[pos][k^1],fa[ch[f][k]]=f,fa[f]=pos,ch[pos][k^1]=f,fa[pos]=ff;
     56     if(ff) ch[ff][ch[ff][1]==f]=pos;
     57     upd(f);upd(pos);
     58 }
     59 void splay(int x)
     60 {
     61     for(int f;f=fa[x];rotate(x))
     62         if(fa[f]) rotate((which(x)==which(f)?f:x));
     63     rt=x;
     64 }
     65 void Insert(int x)
     66 {
     67     int pos=rt,f=0;
     68     while(1)
     69     {
     70         if(val[pos]==x) {cnt[pos]++,upd(pos);upd(f);splay(pos);return ;}
     71         f=pos,pos=ch[pos][x>val[pos]];
     72         if(!pos)
     73         {
     74             ch[++sz][0]=ch[sz][1]=0,fa[sz]=f,val[sz]=x,cnt[sz]=size[sz]=1,ch[f][x>val[f]]=sz;
     75             upd(f);splay(sz);return ;
     76         }
     77     }
     78 }
     79 void insert(int x)
     80 {
     81     if(!rt) {val[++sz]=x,ch[sz][0]=ch[sz][1]=fa[sz]=0,cnt[sz]=size[sz]=1,rt=sz;return;}
     82     Insert(x);
     83 }
     84 int find_rank(int x)
     85 {
     86     int res=0,pos=rt;
     87     while(1)
     88     {
     89         if(x<val[pos]) pos=ch[pos][0];
     90         else
     91         {
     92             res+=size[ch[pos][0]];
     93             if(val[pos]==x) {splay(pos);return res+1;}
     94             res+=cnt[pos],pos=ch[pos][1];
     95         }
     96     }
     97 }
     98 void dlt(int x)
     99 {
    100     if(cnt[rt]>1) {cnt[rt]--;return ;}
    101     if(!ch[rt][0]&&!ch[rt][1]) {rt=0;return ;}
    102     if(!ch[rt][0]||!ch[rt][1])
    103     {
    104         int k=!ch[rt][1]?0:1;
    105         rt=ch[rt][k],fa[rt]=0;
    106         return ;
    107     }
    108     int k=find_pre(),tmp=rt;
    109     splay(k);fa[ch[tmp][1]]=rt;
    110     ch[rt][1]=ch[tmp][1],rt=k;
    111 }
    112 int n,m,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1],Val[MAXN<<1],Cnt;
    113 int f[MAXN][20],dep[MAXN],s[MAXN],k[MAXN],tot,hsh[MAXN],HSH[MAXN],vis[MAXN];
    114 ll ans,dis[MAXN];
    115 void add(int u,int v,int w) {nxt[++Cnt]=fst[u],fst[u]=Cnt,to[Cnt]=v,Val[Cnt]=w;}
    116 void dfs(int x)
    117 {
    118     for(int i=1;(1<<i)<=dep[x];i++) f[x][i]=f[f[x][i-1]][i-1];
    119     hsh[x]=++tot,HSH[tot]=x;
    120     for(int i=fst[x];i;i=nxt[i])
    121         if(to[i]!=f[x][0])
    122         {
    123             dis[to[i]]=dis[x]+Val[i],dep[to[i]]=dep[x]+1;
    124             f[to[i]][0]=x;dfs(to[i]);
    125         }
    126 }
    127 int lca(int u,int v)
    128 {
    129     int t;
    130     if(dep[u]<dep[v]) swap(u,v);
    131     t=dep[u]-dep[v];
    132     for(int i=0;i<20;i++)
    133         if((1<<i)&t) u=f[u][i];
    134     if(u==v) return u;
    135     for(int i=19;i>=0;i--)
    136         if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
    137     return f[u][0];
    138 }
    139 inline ll calc(int u,int v) {return dis[HSH[u]]+dis[HSH[v]]-(dis[lca(HSH[u],HSH[v])]<<1);}
    140 int main()
    141 {
    142     n=read(),m=read();int a,b,c;
    143     for(int i=1;i<n;i++) {a=read(),b=read(),c=read();add(a,b,c);add(b,a,c);}
    144     dfs(1);
    145     while(m--)
    146     {
    147         c=hsh[read()],vis[c]^=1;
    148         if(vis[c])
    149         {
    150             if(!rt) {puts("0");insert(c);continue;}insert(c);
    151             a=val[find_pre()],b=val[find_sub()];
    152             if(!a) a=val[find_max()];if(!b) b=val[find_min()];
    153             if(!a) a=val[rt];if(!b) b=val[rt];
    154             ans+=calc(a,c)+calc(b,c)-calc(a,b);
    155         }
    156         else
    157         {
    158             a=find_rank(c);
    159             a=val[find_pre()],b=val[find_sub()];
    160             if(!a) a=val[find_max()];if(!b) b=val[find_min()];
    161             if(!a) a=val[rt];if(!b) b=val[rt];
    162             ans-=calc(a,c)+calc(b,c)-calc(a,b);
    163             dlt(c);
    164         }
    165         printf("%lld
    ",ans);
    166     }
    167 }
    View Code
  • 相关阅读:
    系统边界确定
    用例分析技术:确定系统边界
    系统边界的定义
    【转】读《程序员修炼之道》
    项目管理之需求基线管理
    字符串流sstream[part3/使用字符串流进行安全的类型转换]
    字符串流sstream[part2/使用同一个字符串流反复读写数据]
    字符串流sstream[part1/基本知识]
    文件操作的openmode
    文件操作的一些函数
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/9676213.html
Copyright © 2011-2022 走看看