BZOJ3924: [Zjoi2015]幻想乡战略游戏(动态点分治)

Description

 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dv×dist(u,v)的金钱来补给这些军队。由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的距离(唯一路径的权和)。 因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。

Input

第一行两个数n和Q分别表示树的点数和幽香操作的个数,其中点从1到n标号。 
接下来n-1行,每行三个正整数a,b,c,表示a和b之间有一条边权为c的边。 
接下来Q行,每行两个数u,e,表示幽香在点u上放了e单位个军队
(如果e<0,就相当于是幽香在u上减少了|e|单位个军队,说白了就是du←du+e)。
数据保证任何时刻每个点上的军队数量都是非负的。 
1<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5
对于所有数据,这个树上所有点的度数都不超过20
N,Q>=1

Output

 对于幽香的每个操作,输出操作完成以后,每天的最小花费,也即如果幽香选择最优的补给点进行补给时的花费。 

Sample Input

10 5
1 2 1
2 3 1
2 4 1
1 5 1
2 6 1
2 7 1
5 8 1
7 9 1
1 10 1
3 1
2 1
8 1
3 1
4 1

Sample Output

0
1
4
5
6

解题思路:

相当于动态统计一棵树的带权重心。

怎么搞呢?

序列上会不会。

不就是二分吗,这东西会形成一个单峰函数。

证明我不会不过可以拿这个代码看一下。

#include<cstdio>
#include<algorithm>
typedef long long lnt;
const int N=10;
int a[]={0,101,2131,321,432,213,3124,5342,2323,5432,2323,
             122,2511,321,432,2513,3132,5342,2323,5432,2323,
           102,211,321,432,2133,3124,5342,2323,5432,2323,
           12,2131,321,43124,52323,5432,2323,
           102,231,21,43413224,5342,323,5432,3,
           153,2131,213213,3124,5342,2323,543323,
           102,21,321,43242,233,5432,2323,
           502,2131,321,4,5342,2323,5432,2323
           102,2131,321,53,2323,5432,2323,
           12302,2131,3212,432,122342,2323,5432,2323,
           103212,2131,321,432,21324,5312,28323,5432,23
           1102,2131,321,432,213,3124,5342,2323,5432,3,
           1023,2131,321,432,213,31124,5342,2323,543223,
           103212,2131,321,432,213,3124,5342,2323,5432,3,
           102,2131,321,432,5213,3124,5342,2323,5432,2323,
           102,2131,321,432,213,3124,5342,2323,5432,2323,};
lnt fan(int pos)
{
    lnt ans=0;
    for(int i=1;i<=N;i++)
    {
        ans+=1ll*std::abs(pos-i)*a[i];
    }
    return ans;
}
int main()
{
    for(int i=1;i<=N;i++)
        printf("%I64d ",fan(i));
    return 0;
}
View Code

所以就是单峰了。

所以说就可以在树上做同样的试探动作。

如果一个点的答案更优秀那么答案就在其子树中。

可以知道一个点答案就是向父亲走时加入容斥。

那个公式我就不推了QAQ。

维护三个答案,子到父代价,子树代价,子树全职和。

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 typedef long long lnt;
  5 const int N=100010;
  6 struct pnt{
  7     int fa;
  8     int hd;
  9     int hf;
 10     int dp;
 11     int wgt;
 12     int ind;
 13     lnt dis;
 14     lnt sum;
 15     lnt diss;
 16     lnt disf;
 17     bool vis;
 18 }p[N];
 19 struct ent{
 20     int twd;
 21     int lst;
 22     lnt vls;
 23 }e[N<<2];
 24 int rt;
 25 int n,m;
 26 int cnt;
 27 int dfn;
 28 int root;
 29 int size;
 30 int maxsize;
 31 int lg[N<<2];
 32 int eula[N<<2][21];
 33 void ade(int f,int t,lnt v)
 34 {
 35     cnt++;
 36     e[cnt].twd=t;
 37     e[cnt].vls=v;
 38     e[cnt].lst=p[f].hd;
 39     p[f].hd=cnt;
 40     return ;
 41 }
 42 void adf(int f,int t,int lin)
 43 {
 44     cnt++;
 45     e[cnt].twd=t;
 46     e[cnt].vls=lin;
 47     e[cnt].lst=p[f].hf;
 48     p[f].hf=cnt;
 49     return ;
 50 }
 51 void E_dfs(int x,int f)
 52 {
 53     eula[++dfn][0]=x;
 54     p[x].ind=dfn;
 55     p[x].dp=p[f].dp+1;
 56     for(int i=p[x].hd;i;i=e[i].lst)
 57     {
 58         int to=e[i].twd;
 59         if(to==f)
 60             continue;
 61         p[to].dis=p[x].dis+e[i].vls;
 62         E_dfs(to,x);
 63         eula[++dfn][0]=x;
 64     }
 65     return ;
 66 }
 67 int Emin(int x,int y)
 68 {
 69     return p[x].dp<p[y].dp?x:y;
 70 }
 71 int Lca(int x,int y)
 72 {
 73     x=p[x].ind;
 74     y=p[y].ind;
 75     if(x>y)
 76         std::swap(x,y);
 77     int l=lg[y-x+1];
 78     return Emin(eula[x][l],eula[y-(1<<l)+1][l]);
 79 }
 80 lnt Dis(int x,int y)
 81 {
 82     int z=Lca(x,y);
 83     return p[x].dis+p[y].dis-2*p[z].dis;
 84 }
 85 void grc_dfs(int x,int f)
 86 {
 87     p[x].wgt=1;
 88     int maxs=-1;
 89     for(int i=p[x].hd;i;i=e[i].lst)
 90     {
 91         int to=e[i].twd;
 92         if(to==f||p[to].vis)
 93             continue;
 94         grc_dfs(to,x);
 95         p[x].wgt+=p[to].wgt;
 96         if(p[to].wgt>maxs)
 97             maxs=p[to].wgt;
 98     }
 99     maxs=std::max(maxs,size-p[x].wgt);
100     if(maxs<maxsize)
101     {
102         maxsize=maxs;
103         root=x;
104     }
105     return ;
106 }
107 void bin_dfs(int x,int f)
108 {
109     p[x].fa=f;
110     p[x].vis=true;
111     int tmp=size;
112     for(int i=p[x].hd;i;i=e[i].lst)
113     {
114         int to=e[i].twd;
115         if(p[to].vis)
116             continue;
117         root=0;
118         if(p[x].wgt<p[to].wgt)
119             size=tmp-p[x].wgt;
120         else
121             size=p[to].wgt;
122         maxsize=0x3f3f3f3f;
123         grc_dfs(to,to);
124         adf(x,root,to);
125         bin_dfs(root,x);
126     }
127     return ;
128 }
129 void update(int x,lnt y)
130 {
131     p[x].sum+=y;
132     for(int i=x;p[i].fa;i=p[i].fa)
133     {
134         p[p[i].fa].sum+=y;
135         lnt tmp=Dis(x,p[i].fa)*y;
136         p[i].disf+=tmp;
137         p[p[i].fa].diss+=tmp;
138     }
139     return ;
140 }
141 lnt assess(int x)
142 {
143     lnt ans=p[x].diss;
144     for(int i=x;p[i].fa;i=p[i].fa)
145     {
146         lnt tmp=Dis(x,p[i].fa);
147         ans+=tmp*(p[p[i].fa].sum-p[i].sum);
148         ans+=p[p[i].fa].diss-p[i].disf;
149     }
150     return ans;
151 }
152 lnt Query(void)
153 {
154     bool has=true;
155     lnt ans=assess(rt);
156     int lastpos=rt;
157     while(has)
158     {
159         has=false;
160         for(int i=p[lastpos].hf;i;i=e[i].lst)
161         {
162             int to=e[i].twd;
163             lnt tmp=assess(e[i].vls);
164             if(tmp<ans)
165             {
166                 has=true;
167                 ans=assess(to);
168                 lastpos=to;
169                 break;
170             }
171         }
172     }
173     return ans;
174 }
175 int main()
176 {
177     scanf("%d%d",&n,&m);
178     for(int i=1;i<n;i++)
179     {
180         int a,b;
181         lnt c;
182         scanf("%d%d%lld",&a,&b,&c);
183         ade(a,b,c);
184         ade(b,a,c);
185     }
186     E_dfs(1,1);
187     for(int i=2;i<=dfn;i++)
188         lg[i]=lg[i>>1]+1;
189     for(int i=1;i<=20;i++)
190         for(int j=1;j+(1<<i)-1<=dfn;j++)
191             eula[j][i]=Emin(eula[j][i-1],eula[j+(1<<(i-1))][i-1]);
192     root=0;
193     size=n;
194     maxsize=0x3f3f3f3f;
195     grc_dfs(1,1);
196     rt=root;
197     bin_dfs(root,0);
198     while(m--)
199     {
200         int x,y;
201         scanf("%d%d",&x,&y);
202         update(x,y);
203         printf("%lld\n",Query());
204     }
205     return 0;
206 }

 

posted @ 2018-12-22 11:20  Unstoppable728  阅读(209)  评论(0编辑  收藏  举报