ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

<题解>幻想乡战略游戏

2021-06-14 08:32:46  阅读:199  来源: 互联网

标签:幻想 son 游戏 树状 int top 点分 战略 树上


洛谷题目

看到题面,很容易就想到,这是要你找树上的重心,只不过这个重心是在带边权的树上

所以对于这个我们在树上找这个重心

一开始我想的是,我要更新权值,然后把每个点的答案更新一下

就取最大值,这好像是O(....),我也不会算这个复杂度,好像太大了

后来去学习了一下,点分树;;

知道了有点分树这个东西,立刻就想到

如果我们在点分树上寻找这个带权重心,是不是就可以保证复杂度了???

我先去打了板子,就是上一篇博客,一开始我就想用树状数组

然后我发现自己狭隘了,用树状数组根本维护不了每个点的军队数量

然后我就想别的办法,想不出来,颓一发题解,可是刚看到题解,他竟然没用树状数组,而是维护了两个数组,一个存答案,一个存数量

和树状数组的思想类似,还是要维护两个值,维护自己的,维护爹的,不过这里还有另外一个套路

  ans加上爹的,减去自己的,还要加上x到爹的价值

然后还有一道题也是这样维护,没啥意思,不过那个题调了一晚上加上一早起(MLE+TLE),为啥呢? 手残打错一个变量;

所以这个题就这样做,加入军队就是在点分树上更新,然后记录一下第一次树的重心,然后由这个树根沿着点分树的父子关系向下搜索

所以我们还要开另外一个临界表来存储他们的儿子;

记得我们判断答案是否在他这个儿子里,要在原树上判断,一开始就在点分树上判断,WA了好几遍

然后搜索的时候,要回到点分树上搜索。。。。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define int long long
  4 #define re register int 
  5 const int N=100005;
  6 int n,m;
  7 int to[N<<1],nxt[N<<1],val[N<<1],head[N],rp;
  8 void add_edg(int x,int y,int z){
  9     to[++rp]=y;val[rp]=z;nxt[rp]=head[x];head[x]=rp;
 10 }
 11 int siz[N],son[N],dep[N],len[N],fa[N],top[N];
 12 void dfs1(int x,int f){
 13     siz[x]=1;
 14     dep[x]=dep[f]+1;fa[x]=f;
 15     for(re i=head[x];i;i=nxt[i]){
 16         int y=to[i];
 17         if(y==f)continue;
 18         len[y]=len[x]+val[i];
 19         dfs1(y,x);
 20         siz[x]+=siz[y];
 21         if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
 22     }
 23 }
 24 void dfs2(int x,int f){
 25     top[x]=f;
 26     if(son[x])dfs2(son[x],f);
 27     for(re i=head[x];i;i=nxt[i]){
 28         int y=to[i];
 29         if(y==fa[x]||y==son[x])continue;
 30         dfs2(y,y);
 31     }
 32 }
 33 int get_lca(int x,int y){
 34     while(top[x]!=top[y]){
 35         if(dep[top[x]]<dep[top[y]])swap(x,y);
 36         x=fa[top[x]];
 37     }
 38     return dep[x]<dep[y]?x:y;
 39 }
 40 int get_dis(int x,int y){
 41     return len[x]+len[y]-2*len[get_lca(x,y)];
 42 }
 43 int rt,alsiz,mx,ms[N];
 44 bool vis[N];
 45 void get_rt(int x,int f){
 46     siz[x]=1;ms[x]=0;
 47     for(re i=head[x];i;i=nxt[i]){
 48         int y=to[i];
 49         if(y==f||vis[y])continue;
 50         get_rt(y,x);
 51         siz[x]+=siz[y];
 52         ms[x]=max(ms[x],siz[y]);
 53     }
 54     ms[x]=max(ms[x],alsiz-siz[x]);
 55     if(ms[x]<mx)mx=ms[x],rt=x;
 56 }
 57 void get_siz(int x,int f){
 58     siz[x]=1;
 59     for(re i=head[x];i;i=nxt[i]){
 60         int y=to[i];
 61         if(y==f||vis[y])continue;
 62         get_siz(y,x);
 63         siz[x]+=siz[y];
 64     }
 65 }
 66 int newfa[N];
 67 int t[N<<1],nx[N<<1],he[N<<1],va[N<<1],r;
 68 void add_ed(int x,int y,int z){
 69     t[++r]=y;
 70     va[r]=z;
 71     nx[r]=he[x];
 72     he[x]=r;
 73 }
 74 void pre_dfs(int x){
 75     vis[x]=1;get_siz(x,0);
 76     for(re i=head[x];i;i=nxt[i]){
 77         //cout<<"sb"<<rt<<endl;
 78         int y=to[i];
 79         if(vis[y])continue;
 80         alsiz=mx=siz[y];get_rt(y,0);
 81         add_ed(x,y,rt);
 82         newfa[rt]=x;pre_dfs(rt);
 83     }
 84 }
 85 int sum1[N],sum2[N];
 86 int siz1[N],siz2[N];
 87 void get_up(int x,int v){
 88     for(re i=x;i;i=newfa[i])sum1[i]+=get_dis(i,x)*v,siz1[i]+=v;
 89     for(re i=x;newfa[i];i=newfa[i])sum2[i]+=get_dis(newfa[i],x)*v,siz2[i]+=v;
 90 }
 91 int get_sum(int x){
 92     int ret=sum1[x];
 93     for(re i=x;newfa[i];i=newfa[i]){
 94         ret+=sum1[newfa[i]];
 95         ret-=sum2[i];
 96         ret+=get_dis(newfa[i],x)*(siz1[newfa[i]]-siz2[i]);
 97     }
 98     return ret;
 99 }
100 int get_ans(int x){
101     int ret=get_sum(x);
102     for(re i=he[x];i;i=nx[i]){
103         if(get_sum(t[i])<ret)return get_ans(va[i]);
104     }
105     return ret;
106 }
107 signed main(){
108     scanf("%lld%lld",&n,&m);
109     for(re i=1;i<n;i++){
110         int x,y,z;
111         scanf("%lld%lld%lld",&x,&y,&z);
112         add_edg(x,y,z);add_edg(y,x,z);
113     }
114     dfs1(1,0);
115     dfs2(1,1);
116     alsiz=mx=n;
117     get_rt(1,0);
118     //cout<<rt<<endl;
119     pre_dfs(rt);
120     memset(vis,0,sizeof(vis));
121     alsiz=mx=n;
122     get_rt(1,0);
123     //cout<<rt<<endl;
124     for(re i=1;i<=m;i++){
125         int x,y;
126         scanf("%lld%lld",&x,&y);
127         get_up(x,y);
128         //cout<<rt<<" ";
129         printf("%lld\n",get_ans(rt));
130     }
131 }
View Code

所以对于点分树的题,第一找好这个题寻找的是啥

第二搞对容斥,就上面那个公式

第三打代码得细心,细节太多了

这类题多会求lca,我习惯用树链剖分,好大也好看

注意距离和深度不是一回事,找lca用深度,找dis用距离(权值);

标签:幻想,son,游戏,树状,int,top,点分,战略,树上
来源: https://www.cnblogs.com/hzoi-fengwu/p/14881811.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有