• 【BZOJ】【3991】【SDOI2015】寻宝游戏


    dfs序


      我哭啊……这题在考试的时候(我不是山东的,CH大法吼)没想出来……只写了50分的暴力QAQ

      而且苦逼的写的比正解还长……我骗点分容易吗QAQ

      骗分做法:

      1.$n,mleq 1000$: 直接找一个关键点做根进行深搜,算出其他关键点都与root连通的最小边权和,再×2

      2.一条链的情况:用set维护序列中哪些点选了,然后ans=(sum[tail]-sum[head])*2; 其中sum[i]表示从序列首到第 i 个的边长之和……嗯就是前缀和优化一下= =取首和尾这一段的Len之和

      3.保证第一次一定变动1号村庄,且以后1不再变动:以1为根,每次update(x),将从x到1的所有边更新一遍,看有多少个点需要经过它,如果是新加的边就在ans中加进来,如果这次删点后这条边无用了,就在ans中减去

      以上就是50分的骗分做法……写起来倒是不难(正解写起来更简单QAQ)

      1 //Huce #4 B
      2 #include<set>
      3 #include<vector>
      4 #include<cstdio>
      5 #include<cstdlib>
      6 #include<cstring>
      7 #include<iostream>
      8 #include<algorithm>
      9 #define rep(i,n) for(int i=0;i<n;++i)
     10 #define F(i,j,n) for(int i=j;i<=n;++i)
     11 #define D(i,j,n) for(int i=j;i>=n;--i)
     12 using namespace std;
     13 
     14 int getint(){
     15     int v=0,sign=1; char ch=getchar();
     16     while(ch<'0'||ch>'9') {if (ch=='-') sign=-1; ch=getchar();}
     17     while(ch>='0'&&ch<='9') {v=v*10+ch-'0'; ch=getchar();}
     18     return v*sign;
     19 }
     20 typedef long long LL;
     21 const int N=100010,INF=~0u>>2;
     22 /*******************tamplate********************/
     23 int head[N],to[N<<1],next[N<<1],len[N<<1],cnt;
     24 void add(int x,int y,int z){
     25     to[++cnt]=y; next[cnt]=head[x]; len[cnt]=z; head[x]=cnt;
     26     to[++cnt]=x; next[cnt]=head[y]; len[cnt]=z; head[y]=cnt;
     27 }
     28 /*********************edge**********************/
     29 int n,m,du[N];
     30 bool sign[N],vis[N];
     31 
     32 namespace work1{
     33     LL ans;
     34     bool dfs(int x){
     35         bool tmp=sign[x];
     36         vis[x]=1;
     37         for(int i=head[x];i;i=next[i]) if(!vis[to[i]]){
     38             if (dfs(to[i])){
     39                 ans+=len[i];
     40                 tmp=1;
     41             }
     42         }
     43         return tmp;
     44     }
     45     LL solve(){
     46         ans=0;
     47         memset(vis,0,sizeof vis);
     48         F(i,1,n) if (sign[i]){
     49             dfs(i);
     50             return ans;
     51         }
     52     }
     53     void work1(){
     54         int x;
     55         F(i,1,m){
     56             x=getint(); sign[x]^=1;
     57             printf("%lld
    ",solve()*2);
     58         }
     59     }
     60 }
     61 namespace work2{
     62     int a[N],tot,num[N];
     63     LL sum[N];
     64     void dfs(int x,int l){
     65         vis[x]=1;
     66         a[++tot]=x;
     67         sum[tot]=sum[tot-1]+l;
     68         num[x]=tot;
     69         for(int i=head[x];i;i=next[i])
     70             if (!vis[to[i]])
     71                 dfs(to[i],len[i]);
     72     }
     73     set<int>s;
     74     set<int>::iterator it;
     75     void work2(){
     76         F(i,1,n) if (du[i]==1){
     77             dfs(i,0);
     78             break;
     79         }
     80 //        F(i,1,tot) printf("%d ",a[i]);puts("");
     81         int x;
     82         F(i,1,m){
     83             x=getint();
     84             sign[x]^=1;
     85             if (sign[x]) s.insert(num[x]);
     86             else{
     87                 it=s.find(num[x]);
     88                 s.erase(it);
     89             }
     90             it=s.end(); it--;
     91 //            printf("%d %d
    ",*s.begin(),*s.rbegin());
     92             printf("%lld
    ",(sum[*s.rbegin()]-sum[*s.begin()])*2);
     93         }
     94     }
     95 }
     96 namespace work3{
     97     int fa[N],num[N],dis[N];
     98     LL ans;
     99     bool vis[N];
    100     void dfs(int x){
    101         vis[x]=1;
    102         for(int i=head[x];i;i=next[i])
    103             if (!vis[to[i]]){
    104                 fa[to[i]]=x;
    105                 dis[to[i]]=len[i];
    106                 dfs(to[i]);
    107             }
    108     }
    109     void update(int x,int v){
    110         if (x==1) return;
    111         if (v==1){
    112             num[x]++;
    113             if (num[x]==1) ans+=dis[x];
    114         }else{
    115             num[x]--;
    116             if (num[x]==0) ans-=dis[x];
    117         }
    118         update(fa[x],v);
    119     }
    120     void work3(){
    121         int x;
    122         memset(vis,0,sizeof vis);
    123         dfs(1);
    124 //        F(i,1,n) printf("%d ",dis[i]); puts("");
    125         F(i,1,m){
    126             x=getint(); sign[x]^=1;
    127             update(x,sign[x]?1:-1);
    128             printf("%lld
    ",ans*2);
    129         }
    130     }
    131 }
    132 int main(){
    133 #ifndef ONLINE_JUDGE
    134     freopen("B.in","r",stdin);
    135 //    freopen("output.txt","w",stdout);
    136 #endif
    137     n=getint(); m=getint();
    138     int x,y,z,mx=0;
    139     F(i,2,n){
    140         x=getint(); y=getint(); z=getint();
    141         add(x,y,z);
    142         du[x]++; du[y]++;
    143         mx=max(mx,max(du[x],du[y]));
    144     }
    145     if (n<=1000) work1::work1();
    146     else if (mx==2)    work2::work2();
    147     else 
    148         work3::work3();
    149     return 0;
    150 }
    50分暴力

      其实从骗分2的做法再仔细想想就可以推广到整棵树的情况了:将整个树的dfs序搞出来,那么$ans=sum dfs序中相邻两点的dist$,其中第一个点与最后一个点视为相邻。

      然后用set维护一下点之间的相邻状态(按dfs序排序后,其实就跟上面链的感觉差不多),更新答案就可以了(dist(i,j)可以用从根到 i ,j 以及LCA(i,j)的距离O(logn)算出来)

      QAQ我还是too young too naive

      1 /**************************************************************
      2     Problem: 3991
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:7188 ms
      7     Memory:19016 kb
      8 ****************************************************************/
      9  
     10 //Huce #4 B
     11 #include<set>
     12 #include<vector>
     13 #include<cstdio>
     14 #include<cstdlib>
     15 #include<cstring>
     16 #include<iostream>
     17 #include<algorithm>
     18 #define rep(i,n) for(int i=0;i<n;++i)
     19 #define F(i,j,n) for(int i=j;i<=n;++i)
     20 #define D(i,j,n) for(int i=j;i>=n;--i)
     21 using namespace std;
     22  
     23 int getint(){
     24     int v=0,sign=1; char ch=getchar();
     25     while(ch<'0'||ch>'9') {if (ch=='-') sign=-1; ch=getchar();}
     26     while(ch>='0'&&ch<='9') {v=v*10+ch-'0'; ch=getchar();}
     27     return v*sign;
     28 }
     29 typedef long long LL;
     30 const int N=100010,INF=~0u>>2;
     31 /*******************tamplate********************/
     32 int head[N],to[N<<1],next[N<<1],len[N<<1],cnt;
     33 void add(int x,int y,int z){
     34     to[++cnt]=y; next[cnt]=head[x]; len[cnt]=z; head[x]=cnt;
     35     to[++cnt]=x; next[cnt]=head[y]; len[cnt]=z; head[y]=cnt;
     36 }
     37 /*********************edge**********************/
     38 bool sign[N],vis[N];
     39 int n,m,a[N],tot,num[N],fa[N][20],dep[N];
     40 LL d[N]; 
     41 void dfs(int x){
     42     a[++tot]=x;
     43     num[x]=tot;
     44     F(i,1,17)
     45         if (dep[x]>=(1<<i)) fa[x][i]=fa[fa[x][i-1]][i-1];
     46         else break;
     47     for(int i=head[x];i;i=next[i])
     48         if (to[i]!=fa[x][0]){
     49             fa[to[i]][0]=x;
     50             dep[to[i]]=dep[x]+1;
     51             d[to[i]]=d[x]+len[i];
     52             dfs(to[i]);
     53         }
     54 }
     55 int LCA(int x,int y){
     56     if (dep[x]<dep[y]) swap(x,y);
     57     int t=dep[x]-dep[y];
     58     F(i,0,17) if (t&(1<<i)) x=fa[x][i];
     59     D(i,17,0) if (fa[x][i]!=fa[y][i])
     60         x=fa[x][i],y=fa[y][i];
     61     if (x==y) return x;
     62     return fa[x][0];
     63 }
     64 LL dis(int a,int b){
     65     return d[a]+d[b]-2*d[LCA(a,b)];
     66 }
     67 set<int>s;
     68 typedef set<int>::iterator SI;
     69 LL ans=0;
     70 void work(){
     71     dfs(1);
     72     int x;
     73     SI pre,suc,it;
     74     F(i,1,m){
     75         x=getint();
     76         sign[x]^=1;
     77         if (sign[x]){
     78             suc=pre=it=s.insert(num[x]).first;
     79             if (pre==s.begin()) pre=s.end(); pre--;
     80             suc++; if (suc==s.end()) suc=s.begin();
     81             ans-=dis(a[*suc],a[*pre]);
     82             ans+=dis(a[*suc],a[*it])+dis(a[*it],a[*pre]);
     83         }else{
     84             suc=pre=it=s.find(num[x]);
     85             if (pre==s.begin()) pre=s.end(); pre--;
     86             suc++; if (suc==s.end()) suc=s.begin();
     87             ans-=dis(a[*suc],a[*it])+dis(a[*it],a[*pre]);
     88             ans+=dis(a[*suc],a[*pre]);
     89             s.erase(it);
     90         }
     91         printf("%lld
    ",ans);
     92     }
     93 }
     94 int main(){
     95 #ifndef ONLINE_JUDGE
     96     freopen("B.in","r",stdin);
     97 //  freopen("output.txt","w",stdout);
     98 #endif
     99     n=getint(); m=getint();
    100     int x,y,z,mx=0;
    101     F(i,2,n){
    102         x=getint(); y=getint(); z=getint();
    103         add(x,y,z);
    104     }
    105     work();
    106     return 0;
    107 }
    View Code

    3991: [Sdoi2015]寻宝游戏

    Time Limit: 40 Sec  Memory Limit: 128 MB
    Submit: 125  Solved: 74
    [Submit][Status][Discuss]

    Description

     小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物

    Input

     第一行,两个整数N、M,其中M为宝物的变动次数。

    接下来的N-1行,每行三个整数x、y、z,表示村庄x、y之间有一条长度为z的道路。
    接下来的M行,每行一个整数t,表示一个宝物变动的操作。若该操作前村庄t内没有宝物,则操作后村庄内有宝物;若该操作前村庄t内有宝物,则操作后村庄内没有宝物。

    Output

     M行,每行一个整数,其中第i行的整数表示第i次操作之后玩家找到所有宝物需要行走的最短路程。若只有一个村庄内有宝物,或者所有村庄内都没有宝物,则输出0。

    Sample Input

    4 5
    1 2 30
    2 3 50
    2 4 60
    2
    3
    4
    2
    1

    Sample Output

    0
    100
    220
    220
    280

    HINT

     1<=N<=100000


    1<=M<=100000

    对于全部的数据,1<=z<=10^9

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    docker 安装es
    Redis 和 Zookeeper 到底谁更牛?
    Redisson 看门狗
    记一次线上服务CPU 100%的处理过程
    必须了解的mysql三大日志-binlog、redo log和undo log
    python学习笔记 -- reduce合并减少
    Python学习笔记 -- 列表2: 遍历:嵌套列表, 将其中同位置的元素组成新的列表
    python学习笔记 -- filter() 过滤符合条件的可迭代序列
    python学习笔记 -- map() 操作可迭代序列
    python学习笔记
  • 原文地址:https://www.cnblogs.com/Tunix/p/4442334.html
Copyright © 2020-2023  润新知